• 软件测试进阶篇----自动化测试脚本开发


    自动化测试脚本开发

    一、自动化测试用例开发

    1、用例设计需要注意的点

    image-20230921152728082

    2、设计一条测试用例

    image-20230921152749418

    二、脚本开发过程中的技术

    1、线性脚本开发

    2、模块化脚本开发(封装线性代码到方法或者类中。在需要的地方进行调用)

    3、关键字驱动开发:selenium ide关键字驱动开发

    4、数据驱动开发:数据和脚本分离。数据专门存储在外部的文件中。(结合unittest框架的ddt(data driver test)模块)

    5、po设计模式:将页面中的元素和操作的方法封装在一个页面对象中,只需要调用对象中封装的元素和操作方法来实现测试用例,不需要真实的页面

    三、蜜蜂电商系统的脚本设计-1

    采用python+selenium+unitte实现自动化测试的基本脚本,还会涉及到ddt+json实现数据驱动,git和gitee实现持续集成。

    1、前期准备

    • public:放公共访问、公用的一些模块:发邮件的模块、记录日志的模块、登录模块、登出模块等
    • testcases:放所有采用unittest框架设计的测试用例的模块
      • register
        • mifeng_register.py
        • mifeng_register_username.py
        • mifeng_register_email.py
        • ……
      • login
        • mifeng_login.py
        • mifeng_login_username.py
        • ……
      • search
      • gouwu
      • order
      • pay
    • testdata:测试用例所需要的数据驱动文件,采用json文件
      • mifeng_register.json
      • …….
    • testreport:html格式的测试报告文件
      • 09211412.html
    • testlog:日志文件
    • maintest.py:入口文件、主运行文件

    2、正向注册用例设计

    
    # 采用unittest框架,实现正向注册的用例
    import unittest
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    import time
    
    
    # 单元测试用例
    class mifeng_register(unittest.TestCase):
        def setUp(self):
            # 创建浏览器对象
            self.driver = webdriver.Chrome()
            self.driver.maximize_window()
            self.driver.implicitly_wait(10)
            # 打开某电商首页
            self.driver.get('xxx')
    
        def test_register(self):
            '''正向注册功能测试用例'''
    
            # # 打开蜜蜂电商首页
            # self.driver.get('')
            # 点击首页的“免费注册”按钮
            timestr = time.strftime("%H%M%S")
            username = "blue_" + timestr
            email = username + "@163.com"
            self.driver.find_element(By.LINK_TEXT, '免费注册').click()
            # 输入正向的用户名
            self.driver.find_element(By.ID, 'username').send_keys(username)
            # 输入正向的邮箱
            self.driver.find_element(By.ID, 'email').send_keys(email)
            # 输入正向的密码
            self.driver.find_element(By.ID, 'password').send_keys('123456')
            # 输入正向的确认密码
            self.driver.find_element(By.ID, 'repassword').send_keys('123456')
            # 勾选协议
            # 点击“立即注册”按钮
            self.driver.find_element(By.LINK_TEXT, '立即注册').click()
    
            # 强制等待,先等5s,跳过中间页面
            time.sleep(5)
            # 断言
            sj = self.driver.find_element(By.XPATH, '/html/body/div[4]/div[1]/div[2]/div[1]/div[1]/h3/font[1]').text
            yq = username
            self.assertEqual(yq, sj, '预期结果和实际结果不一致')
    
        def test_register_chongfu(self):
            '''重复注册功能测试用例'''
    
            # 打开电商首页
            self.driver.get('xxx')
            # 点击首页的“免费注册”按钮
            self.driver.find_element(By.LINK_TEXT, '免费注册').click()
            # 输入正向的用户名
            self.driver.find_element(By.ID, 'username').send_keys('blue_002')
            # 输入正向的邮箱
            self.driver.find_element(By.ID, 'email').send_keys('blue_002@163.com')
            # 输入正向的密码
            self.driver.find_element(By.ID, 'password').send_keys('123456')
            # 输入正向的确认密码
            self.driver.find_element(By.ID, 'repassword').send_keys('123456')
            # 勾选协议
            # 点击“立即注册”按钮
            self.driver.find_element(By.LINK_TEXT, '立即注册').click()
    
            # 强制等待,先等5s,跳过中间页面
            time.sleep(5)
            # 断言
            # sj = self.driver.find_element(By.XPATH,'/html/body/div[4]/div[1]/div[2]/div[1]/div[1]/h3/font[1]').text
            sj = self.driver.current_url
            yq = r'xxx'
            # yq='blue_002'
            self.assertEqual(yq, sj, '预期结果和实际结果不一致')
    
        def tearDown(self):
            # 关闭浏览器
            self.driver.quit()
    
    
    if __name__ == '__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    3、主运行文件

    # 主运行文件:获取测试用例集合、运行测试用例集合、得到可视化测试报告....
    import unittest
    from BeautifulReport import BeautifulReport
    import time
    
    # 获取测试集合
    # 获取级联(指定父目录,可以遍历子目录,要求目录必须是包)目录下的测试用例
    discover = unittest.defaultTestLoader.discover(r'./TestCases/',pattern='mifeng*.py')
    print(discover)
    
    # 用时间戳作为测试报告的文件名
    strTime = time.strftime('%m%d%H%M')
    filename = 'report_'+strTime
    
    # 创建运行器对象
    runner = BeautifulReport(discover)
    runner.report('电商自动化测试报告',filename,'./TestReport/')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4、登录模块的测试用例

    # 采用unittest框架,实现正向登录的用例
    import unittest
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    import time
    
    
    # 单元测试用例
    class mifeng_login(unittest.TestCase):
        def setUp(self):
            # 创建浏览器对象
            self.driver = webdriver.Chrome()
            self.driver.maximize_window()
            self.driver.implicitly_wait(10)
            # 打开电商首页
            self.driver.get('xxx')
    
        def test_login_01(self):
            '''正常登录的测试用例'''
            # self.driver.get('xxx')
            self.driver.find_element(By.LINK_TEXT, '登陆').click()
            # 输入用户名和密码(正向数据)
            self.driver.find_element(By.ID, 'username').send_keys('blue_001')
            self.driver.find_element(By.ID, 'password').send_keys('123456')
            # 点击登陆按钮
            self.driver.find_element(By.XPATH, '//*[@id="login-form"]/div/a').click()
            # 断言
            time.sleep(5)
            sj = self.driver.find_element(By.XPATH, '/html/body/div[4]/div[1]/div[2]/div[1]/div[1]/h3/font[1]').text
            yq = 'blue_001'
            self.assertEqual(yq, sj, '预期结果和实际结果不一致!!!')
    
        def test_login_02(self):
            '''登录用户名为空的测试用例'''
            # self.driver.get('xxx')
            self.driver.find_element(By.LINK_TEXT, '登陆').click()
            # 用户名设置为空
            self.driver.find_element(By.ID, 'username').send_keys('')
            self.driver.find_element(By.ID, 'password').send_keys('123456')
            # 点击登陆按钮
            self.driver.find_element(By.XPATH, '//*[@id="login-form"]/div/a').click()
            # 断言
            time.sleep(5)
            sj = self.driver.find_element(By.XPATH, '//*[@id="login-form"]/div/dl[1]/dd/span/font').text
            yq = '请输入用户名'
            self.assertEqual(yq, sj, '预期结果和实际结果不一致!!!')
    
        def test_login_03(self):
            '''未注册用户名登录的测试用例'''
            # self.driver.get('xxx')
            self.driver.find_element(By.LINK_TEXT, '登陆').click()
            # 用户名设置为空
            self.driver.find_element(By.ID, 'username').send_keys('blue01')
            self.driver.find_element(By.ID, 'password').send_keys('123456')
            # 点击登陆按钮
            self.driver.find_element(By.XPATH, '//*[@id="login-form"]/div/a').click()
            # 断言
            time.sleep(5)
            sj = self.driver.current_url
            yq = 'xxx'
            self.assertEqual(yq, sj, '预期结果和实际结果不一致!!!')
    
        def tearDown(self):
            self.driver.quit()
    
    
    if __name__ == '__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    5、级联目录下的用例获取

    # 主运行文件:获取测试用例集合、运行测试用例集合、得到可视化测试报告....
    import unittest
    from BeautifulReport import BeautifulReport
    import time
    
    # 获取测试集合
    # 获取级联(指定父目录,可以遍历子目录,要求目录必须是包)目录下的测试用例
    discover = unittest.defaultTestLoader.discover(r'./TestCases/',pattern='mifeng*.py')
    print(discover)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6、修改个人资料的测试用例

    # 采用unittest框架,实现一个个人资料正常更新的用例
    # 先登录--更新资料--退出
    import unittest
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    import time
    from 电商项目1.Public.Basic import login,logout
    
    # 单元测试用例
    class mifeng_userinfo(unittest.TestCase):
        def setUp(self):
            # 创建浏览器对象
            self.driver = webdriver.Chrome()
            self.driver.maximize_window()
            self.driver.implicitly_wait(10)
            # 先登录
            login(self.driver)
    
    
        def test_userinfo_01(self):
            '''正向个人资料修改功能测试用例'''
            # 登录成功,改资料
            # 点击个人资料超链接
            self.driver.find_element(By.LINK_TEXT,'个人资料').click()
            time.sleep(2)
            # 设置昵称、QQ和性别、出生日期等
            self.driver.find_element(By.ID, 'nickname').clear()
            self.driver.find_element(By.ID,'nickname').send_keys('王同学')
            self.driver.find_element(By.ID, 'qq').clear()
            self.driver.find_element(By.ID,'qq').send_keys('2659160211')
            self.driver.find_element(By.XPATH,'//*[@id="profile-form"]/dl[3]/dd/label[2]/input').click()
            self.driver.find_element(By.XPATH,'//*[@id="birth_year"]/option[78]').click()
            self.driver.find_element(By.XPATH,'//*[@id="birth_month"]/option[2]').click()
            self.driver.find_element(By.XPATH,'//*[@id="birth_day"]/option[20]').click()
            # 点击更新按钮
            self.driver.find_element(By.CSS_SELECTOR,'#profile-form > div > button').click()
            # 断言
            sj = self.driver.find_element(By.XPATH,'/html/body/div/div[2]/h3').text
            yq = '更新资料成功'
            self.assertEqual(yq,sj)
    
        def test_userinfo_02(self):
            '''更新个人资料头像修改功能测试用例'''
            # 登录成功,改资料
            # 点击个人资料超键
            self.driver.find_element(By.LINK_TEXT,'个人资料').click()
            time.sleep(2)
            # 提交头像
            self.driver.find_element(By.NAME,'avatar_file').send_keys(r'd:/aa.jpg')
            # 保存头像
            self.driver.find_element(By.ID,'save-avatar-btn').click()
    
            # 点击更新按钮
            self.driver.find_element(By.CSS_SELECTOR,'#profile-form > div > button').click()
            # 断言
            sj = self.driver.find_element(By.XPATH,'/html/body/div/div[2]/h3').text
            yq = '更新资料成功'
            self.assertEqual(yq,sj)
    
        def tearDown(self):
            # 退出
            logout(self.driver)
            # 关闭浏览器
            self.driver.quit()
    
    if __name__=='__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    8、数据驱动测试

    对设计过的用例使用数据驱动的方式实现

    数据驱动:由于数据的变化,而导致结果的不同(来实现不同的测试用例)的过程。

    实现数据驱动:数据和脚本步骤分离式管理

    数据的存储方式:

    • json
    • csv
    • excel
    • yaml
    • 数据库–pymysql

    知识点:python+unittest+ddt+json来实现数据驱动

    使用ddt实现数据驱动的步骤:

    • 安装ddt模块:pip install ddt
    • 准备一个json数据文件:
    • 在用例模块中导入ddt的两个类:file_data、ddt
    • @ddt修饰类
    • @file_data(json文件)修饰单元测试用例方法:
    • 单元测试用例方法的参数要和数据文件中保持一致
    • 使用用例的参数替换掉对应的脚本中的常量值

    9、邮件发送

    10、日志记录

    把测试用例执行情况记录在一个文件中,便于后续的查验。

    步骤:

    • 编写logging的配置文件
    • 在主运行文件中调用一次配置文件(和配置文件如何设计有关)
      • 如果配置文件是线性代码,直接导入一次即可
      • 如果配置文件封装在方法中,导入方法并调用一次
      • 如果封装在类中的方法里,导入类、创建对象调方法
    • 测试用例中,导入logging模块
    • logging调用不同等级的日志输出方法
      • fatal()
      • error()
      • info()
      • debug()

    四、代码的版本管理

    版本管理:多人协作、自动化脚本开发的时候,需要进行版本的维护

    1. 版本管理介绍

      • svn:集中式的版本管理工具
      • 分布式版本管理
        • git:版本管理工具
        • gitee:码云,远程仓库
        • github、gitlib:这几个都是主流的仓库
    2. gitee注册

    3. git的版本管理的常见命令

      1. 常见的工作区间

        • workspace:工作区,可以理解为你自己开发代码的文件夹,包含一个.git隐藏文件夹(git init)

        • staging area:暂存区/缓存区(临时存储文件的地方)

        • local repository:本地仓库

        • remote repository:远程仓库

      2. 常见的命令

        • add:将工作区的文件添加到缓存区
        • commit:将缓存区的数据提交到本地仓库
        • git push:将本地仓库的文件上传到远程仓库
        • clone:从远程仓库到本地仓库,一般第一次从远程下载,建议使用
        • pull:从远程仓库到本地工作区,一般已经在本地有了文件版本的情况下使用
      3. 配置SSH公钥

      4. 在gitee上创建一个空的仓库

      5. Git 全局设置:

        git config --global user.name "王同学"
        git config --global user.email "w123456@163.com"
        
        • 1
        • 2
      6. 从本地上传脚本到远程仓库

        先创建本地工作空间

        添加工作空间下的文件到缓存区:

        • git add *:将当前工作区的所有文件都加到缓存区
        • git add a.txt:只加这一个文件

        缓存区数据保存到本地仓库:git commit -m “v1”

        本地仓库和远程仓库建立关联:git remote add origin gitee仓库项目地址

        本地仓库上传到远程仓库:git push -u origin “master”

        回到gitee,刷新仓库

      mkdir blue-mi-feng
      cd blue-mi-feng
      git init 
      touch README.md
      git add README.md
      git commit -m "first commit"
      git remote add origin gitee仓库项目地址
      git push -u origin "master"
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      从远程下载到本地:git clone 地址


    已经可以将自动化代码上传到gitee远程仓库进行管理了。

    后续就可以直接从远程仓库,借助jenkins工具实现自动部署和运行(定时运行,触发运行)

    五、jenkins实现持续集成

    1、jenkins软件的安装

    • 需要jdk11的支持,所以提前安装jdk11(java的语言包)
    • 安装jenkins对应的支持jdk11的版本
    • jenkins软件+插件安装两部分(有一部分安装失败不影响使用)
    • 记住用户名和密码

    2、jenkins的环境变量配置

    作用和windows系统的环境变量配置很相似

    jenkins+git实现自动化部署和执行,需要安装git和gitee插件,作相应的配置即可

    3、插件安装和配置

    1、需要安装git和gitee插件

    2、配置git全局的环境配置

    3、gitee中获取私人令牌

    4、在jenkins中配置gitee参数

    5、添加用户名和密码凭据

    4、创建jenkins任务

    1、新建项目

    2、配置git仓库

    3、触发任务设置

    4、添加window批处理构建

    保存退出

    5、运行任务

    等待设置的定时时间


    六、pom设计模式

    1、pom概述

    ==POM(Page Object Model)==是一种自动化测试设计模式,它将页面对象和测试用例代码分离开来,使测试代码更加清晰和易于维护

    POM模式的核心思想是将每个页面视为一个对象(类),并将页面的元素和操作封装在该对象中。测试代码只需要调用页面对象的方法,而不需要关心页面的具体实现细节。

    POM模式的优点包括:

    1. 提高测试代码的可读性和可维护性:测试代码只需要调用页面对象的方法,而不需要关心页面的具体实现细节,使测试代码更加清晰和易于维护。
    2. 提高测试代码的复用性:页面对象可以在多个测试用例中重复使用,减少了代码的重复编写
    3. 操作提高测试代码的稳定性:页面对象的封装可以避免测试代码对页面元素的直接操作,减少了测试代码对页面的依赖,从而提高了测试代码的稳定性

    POM模式的实现步骤包括:

    1. 封装页面元素定位和操作方法:将页面元素和操作封装在页面对象中,可以使用selenium或其他自动化测试工具提供的API
    2. 创建页面对象:将每个页面视为一个对象,并将页面的元素和操作封装在该对象中进行调用
    3. 编写测试代码:测试代码只需要调用页面对象的方法,而不需要关心页面的具体实现细节
    4. 执行测试用例:执行测试用例时,测试代码会调用页面对象的方法,完成测试操作

    总之,POM模式是一种优秀的自动化测试设计模式,可以提高测试代码的可读性、可维护性、复用性和稳定性。在实际的自动化测试中,可以根据具体的需求和场景选择是否采用POM模式

    image-20230926142405159

    2、做项目目录分层

    • common
      • commondriver.py:封装webdriver api常见的方法
      • 邮件、日志的模块放在该目录下
    • pageobject
      • RegisterPO
      • LoginPO
      • xxxPO
    • testcases
      • login
        • mifeng_login.py
        • mifeng_login_username.py
        • xxx
      • register
        • mifeng_register.py
        • mifeng_register_username.py
        • xxx
      • xxx
    • testreport
    • testlog
    • maintest.py

    3、commondriver设计

    # 实现封装webdriver api方法的,创建浏览器对象、页面打开、页面元素定位、点击、输入、获取文本、切换窗口、弹框、frame等
    # 对开源软件webdriver的二次封装
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    import time
    
    
    class commondriver():
        '''
            功能:构造方法,实现的是变量的初始化
        '''
    
        def __init__(self):
            # 可以先将self.driver变量看作是Chrome浏览器的对象
            # 声明调用的对象,固定写法
            self.driver: webdriver.Chrome = None
    
        # 实现一个打开浏览器的方法,设计一个方法:给不同的参数,可以启动不同的浏览器对象
        def open_browser(self, browser="chrome"):
            '''
            功能:实现一个打开浏览器的方法
            :param browser: 可以是chrome、ff、firefox、safari、edge等
            :return:暂时先不给,后面可以给self.driver
            '''
            if (browser == 'ff' or browser == 'firefox'):
                self.driver = webdriver.Firefox()
            elif (browser == 'edge'):
                self.driver = webdriver.Edge()
            else:
                self.driver = webdriver.Chrome()
            # 实现浏览器的最大化显示,页面元素的隐式等待
            self.driver.maximize_window()
            self.driver.implicitly_wait(10)
            # 在多页面操作的时候,需要使用同一个页面对象
            return self.driver
    
        # 关闭浏览器对象
        def close_browser(self):
            '''
            功能:关闭浏览器对象
            :return:
            '''
            self.driver.quit()
    
        # 打开指定的url地址页面,是需要参数url
        def open_url(self, url=''):
            '''
            功能:打开指定的url地址
            :param url: 页面地址
            :return: 不需要
            '''
            if (url.startswith('http') or url.startswith('https')):
                self.driver.get(url)
            else:
                print('输入的地址不正确,请重新输入!')
    
        # 页面元素定位和操作:self.driver.find_element(By.ZZ,'xx').yy()
        # 定义页面定位方法为私有的,只在本类内调用,其他不能调用
        def __find_element(self, locator=''):
            '''
            功能:通过给定的定位器,来判断是哪一种定位方式(xpath\css\id\linktext)
            :param locator: 是属性值
            :return:element元素对象
            '''
            if (locator.startswith('/') or locator.startswith('//')):
                # 符合上面条件的定位方式是xpath定位
                element = self.driver.find_element(By.XPATH, locator)
            elif (locator.startswith('.') or (locator.startswith('#') or locator.startswith('['))):
                # 符合上面条件的定位方式是css定位
                element = self.driver.find_element(By.CSS_SELECTOR, locator)
            else:
                # 默认是id
                try:
                    element = self.driver.find_element(By.ID, locator)
                except:
                    element = self.driver.find_element(By.LINK_TEXT, locator)
    
            # 返回element页面元素对象
            return element
    
        # 封装文本框的输入方法(具备提前清空功能)
        # 两个参数:定位器locator、输入的数据value
        def input(self, locator='', value=''):
            '''
            功能:定位文本框,清空内容,输入文本
            :param locator: 定位器
            :param value: 输入的值
            :return: 不需要
            '''
            element = self.__find_element(locator)
            element.clear()
            element.send_keys(value)
    
        # 定义一个click点击方法
        def click(self, locator=''):
            '''
            功能:定位元素并点击
            :param locator:
            :return:
            '''
            element = self.__find_element(locator)
            element.click()
    
        # 获取页面元素的文本信息
        def get_text(self, locator=''):
            '''
            功能:获取页面元素的文本信息
            :param locator:
            :return: 返回获取的文本
            '''
            element = self.__find_element(locator)
            return element.text
    
        # switch_to的用法
        def switch_to(self, type='window', locator=''):
            '''
            功能:切换窗口和frame
            :param type:
            :param locator:
            :return:
            '''
    
            if (type == 'frame'):
                element = self.__find_element(locator)
                self.driver.switch_to.frame(element)
            else:
                handles = self.driver.window_handles
                self.driver.switch_to.window(handles[-1])
    
        # 待补充后续需要的方法即可
        def get_current_url(self):
            '''
            获取页面的地址
            :return:
            '''
            return self.driver.current_url
    
    
    if __name__ == '__main__':
        # 创建该类的对象
        cd = commondriver()
        cd.open_browser('')
        # 打开百度页面
        cd.open_url('https://www.baidu.com')
        time.sleep(2)
        # 定位百度文本框并输入CSDN叫我王同学
        cd.input('kw', 'CSDN叫我王同学')
        time.sleep(2)
        # 点击百度一下按钮
        cd.click('su')
        time.sleep(2)
    
        # 关闭浏览器
        cd.close_browser()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154

    4、注册页面对象设计

    # http://shop.mifeng.qfedu.com/
    # 电商注册页面的一些特点:url、用户名、邮箱文本、密码、确认密码文本框、勾选复选框、立即注册按钮、登陆按钮、异常提示信息框
    import time
    from MiFengShopPO.common.commondriver import commondriver
    
    
    # 封装注册页面类,使页面直接继承使用封装好的通用api方法
    class RegisterPage(commondriver):
        # 构造方法:只需要指定注册页面的url地址即可
        def __init__(self,driver):
            '''
            功能:初始化注册页面的地址,直接绑定在类中
            '''
            # 接收外部一个统一的页面对象到当前页面
            self.driver = driver
            self.url = 'xxx'
    
        # 封装注册页面上的用户名文本框:输入值
        def input_username(self, value=''):
            '''
            功能:定位用户名文本框(直接指定使用id属性定位),并且绑定其输入功能
            :param value: 输入的数据
            :return:
            '''
            self.input('username', value)
    
        def input_email(self, value=''):
            '''
            功能:定位邮箱文本框,并且绑定其输入功能
            :param value: 输入的数据
            :return:
            '''
            self.input('email', value)
    
        def input_password(self, value=''):
            '''
            功能:定位密码文本框(直接指定使用id属性定位),并且绑定其输入功能
            :param value: 输入的数据
            :return:
            '''
            self.input('password', value)
    
        def input_repassword(self, value=''):
            '''
            功能:定位确认密码文本框(直接指定使用id属性定位),并且绑定其输入功能
            :param value: 输入的数据
            :return:
            '''
            self.input('repassword', value)
    
        def click_agree(self):
            '''
            功能:定位同意协议(id属性)并点击
            :return:
            '''
            self.click('agree')
    
        def click_registerNow(self):
            '''
            功能:定位立即注册(XPATH)并点击
            :return:
            '''
            self.click('//*[@id="register-form"]/div/div[2]/a')
    
        def click_login(self):
            '''
            功能:定位登陆按钮(XPATH)并点击,LINK_TEXT效率低
            :return:
            '''
            self.click('/html/body/div[2]/div/div/div/div/a')
    
        def get_username_text(self):
            '''
            功能:获取用户名对应的错误提示信息
            :return:返回值是错误信息
            '''
            text = self.get_text('#register-form > div > dl:nth-child(1) > dd > span > font')
            return text
    
        def get_email_text(self):
            '''
            功能:获取邮箱对应的错误提示信息
            :return:返回值是错误信息
            '''
            text = self.get_text('#register-form > div > dl:nth-child(2) > dd > span > font')
            return text
    
        def get_password_text(self):
            '''
            功能:获取密码对应的错误提示信息
            :return:返回值是错误信息
            '''
            text = self.get_text('//*[@id="register-form"]/div/dl[3]/dd/span/font')
            return text
    
        def get_repassword_text(self):
            '''
            功能:获取确认密码对应的错误提示信息
            :return:返回值是错误信息
            '''
            text = self.get_text('//*[@id="register-form"]/div/dl[4]/dd/span/font')
            return text
    
    
    if __name__ == '__main__':
        # 先创建页面
        rp = RegisterPage()
        rp.open_browser()
        rp.open_url(rp.url)
        # 输入用户名为空
        rp.input_username('')
        # 输入邮箱
        rp.input_email('blue_001@163.com')
        # 输入密码
        rp.input_password('123456')
        # 输入确认密码
        rp.input_repassword('123456')
        # 点击立即注册按钮
        rp.click_registerNow()
        time.sleep(1)
        # 断言
        yq = '请设置用户名'
        sj = rp.get_username_text()
        assert yq == sj
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124

    5、测试用例层设计

    import time
    # 反向的注册的用例,结合unittest框架
    import unittest
    from MiFengShopPO.pageobject.RegisterPage import RegisterPage
    
    # 创建单元测试类
    class mifeng_register_username(unittest.TestCase):
        def setUp(self):
            # 创建注册页面对象
            self.rp = RegisterPage()
            # 打开Chrome浏览器
            self.rp.open_browser()
            # 打开电商注册页面
            self.rp.open_url(self.rp.url)
    
    
        def test_register_username_01(self):
            '''
            用户名为空
            :return:
            '''
            self.rp.input_username('')
            self.rp.input_email('blue_012@163.com')
            self.rp.input_password('123456')
            self.rp.input_repassword('123456')
            self.rp.click_registerNow()
            # 断言
            time.sleep(5)
            yq = '请设置用户名'
            sj = self.rp.get_username_text()
            self.assertEqual(yq,sj)
    
        def test_register_username_02(self):
            '''
            用户名为test
            :return:
            '''
            self.rp.input_username('test')
            self.rp.input_email('blue_013@163.com')
            self.rp.input_password('123456')
            self.rp.input_repassword('123456')
            self.rp.click_registerNow()
            # 断言
            time.sleep(5)
            yq = '用户名不符合格式要求'
            sj = self.rp.get_username_text()
            self.assertEqual(yq,sj)
    
        def test_register_username_03(self):
            '''
            用户名为数字开头
            :return:
            '''
            self.rp.input_username('123test')
            self.rp.input_email('blue_014@163.com')
            self.rp.input_password('123456')
            self.rp.input_repassword('123456')
            self.rp.click_registerNow()
            # 断言
            time.sleep(5)
            yq = '用户名不符合格式要求'
            sj = self.rp.get_username_text()
            self.assertEqual(yq,sj)
    
        def test_register_username_04(self):
            '''
            用户名含特殊符号
            :return:
            '''
            self.rp.input_username('ad#¥#¥#¥')
            self.rp.input_email('blue_015@163.com')
            self.rp.input_password('123456')
            self.rp.input_repassword('123456')
            self.rp.click_registerNow()
            # 断言
            time.sleep(5)
            yq = '用户名不符合格式要求'
            sj = self.rp.get_username_text()
            self.assertEqual(yq,sj)
    
    
        def tearDown(self):
            # 关闭浏览器
            self.rp.close_browser()
    
    if __name__ =='__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    6、maintest主运行文件

    import unittest
    from selenium import webdriver
    import time
    from BeautifulReport import BeautifulReport
    
    discover = unittest.defaultTestLoader.discover('./testcases/register',pattern='mifeng_*.py')
    
    filename = 'report_'+time.strftime('%m%d%H%M')
    runner = BeautifulReport(discover)
    runner.report('报告',filename,'./testreport/')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    7、多页面交互设计

    登录用例的实现:涉及到登录页面和中间跳转页面

    import unittest
    from MiFengShopPO.common.commondriver import commondriver
    from MiFengShopPO.pageobject.LoginPage import LoginPage
    from MiFengShopPO.pageobject.TiaoZhuanPage import TiaoZhuanPage
    
    class mifeng_login(unittest.TestCase):
        def setUp(self):
            # 创建一个统一的浏览器对象
            self.driver = commondriver().open_browser()
            # 创建登录的对象,打开登录页面
            self.lp = LoginPage(self.driver)
            self.lp.open_url(self.lp.url)
    
        def test_login_01(self):
            '''
            正向测试用例
            :return:
            '''
            self.lp.input_username('blue_001')
            self.lp.input_password('123456')
            self.lp.click_login()
    
            # 断言:采用跳转页面的元素做断言
            self.tzp = TiaoZhuanPage(self.driver)
            sj = self.tzp.get_tiaozhuan_text()
            yq = '登录成功'
            self.assertEqual(yq,sj)
    
        def tearDown(self):
            self.lp.close_browser()
    
    if __name__=='__main__':
        unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    import unittest
    from MiFengShopPO.common.commondriver import commondriver
    from MiFengShopPO.pageobject.LoginPage import LoginPage
    from MiFengShopPO.pageobject.TiaoZhuanPage import TiaoZhuanPage
    
    class mifeng_login(unittest.TestCase):
        def setUp(self):
            # 创建一个统一的浏览器对象
            self.driver = commondriver().open_browser()
            # 创建登录的对象,打开登录页面
            self.lp = LoginPage(self.driver)
            self.lp.open_url(self.lp.url)
    
        def test_login_01(self):
            '''
            正向测试用例
            :return:
            '''
            self.lp.input_username('blue_001')
            self.lp.input_password('123456')
            self.lp.click_login()
    
            # 断言:采用跳转页面的元素做断言
            self.tzp = TiaoZhuanPage(self.driver)
            sj = self.tzp.get_tiaozhuan_text()
            yq = '登录成功'
            self.assertEqual(yq,sj)
    
        def tearDown(self):
            self.lp.close_browser()
    
    if __name__=='__main__':
        unittest.main()
        ```
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    信息可视化和数据可视化的异同和其他比较,到底怎么区分呢?
    Inter FPGA配置管理SDM(Secure Device Manager)与配置理解
    【Pytest实战】pytest 基本概念及使用大全
    阿里云服务器部署Web环境
    Django + Nginx https部署实战(第一辑)
    2023Etsy入驻攻略——防封安全
    探秘扩散模型:训练算法与采样算法的双重解读
    ALU,半加器,全加器,减法电路
    json-c 理解记录
    运营活动服务端研发总结
  • 原文地址:https://blog.csdn.net/qq_44985444/article/details/134023596