• Pytest电商项目实战(上)



    1.Web自动化登陆及登陆验证处理

    from selenium import webdriver
    
    # 浏览器对象的初始化
    driver = webdriver.Chrome()
    
    # 打开淘宝购物车的登录页面
    driver.get("https://cart.taobao.com/cart.htm")
    
    # 定位到账户名文本框
    driver.find_element("id","fm-login-id").send_keys("云纱璃英")
    driver.find_element("id","fm-login-password").send_keys("xxx")
    driver.find_element("xpath","//div[@class='fm-btn']").click()
    
    
    import os
    
    from selenium import webdriver
    from time import sleep
    # 淘宝登录验证码解决方案
    """
        使用编写的脚本以debug模式启动谷歌浏览器,脚本内容:
        chrome.exe --remote-debugging-port=9222
        必须通过os.popen执行,通过os.system执行命令无效
    """
    
    os.popen("d:/chrome.bat")
    sleep(5)
    
    
    # 加载浏览器驱动
    options = webdriver.ChromeOptions()
    options.debugger_address = '127.0.0.1:9222'
    driver = webdriver.Chrome(options = options)
    sleep(2)
    
    
    # 浏览器对象的初始化
    # driver = webdriver.Chrome()
    
    
    # 打开淘宝购物车的登陆页面
    # driver.get("https://cart.taobao.com/cart.htm")
    #
    # # 定位到账户名文本框
    # driver.find_element_by_id('fm-login-id').send_keys('云纱璃英')
    # # 定位到密码
    # driver.find_element_by_id('fm-login-password').send_keys('xxx')
    #
    # # 点击登陆按钮
    # driver.find_element_by_xpath("//div[@class='fm-btn']").click()
    
    # 点击商品链接
    # driver.find_element_by_xpath("//ul/li[2]/div/div[2]/div/a").click()
    
    driver.find_element_by_xpath("//ul/li[2]/div/div[2]/div[1]/a")
    
    # 浏览器页签切换
    # 获取所有的浏览器页签(句柄)
    handls = driver.window_handles
    print(handls)
    # 切换到新开的第二个页签,下标填1就可以了,下标都是从0开始的
    driver.switch_to.window(handls[1])
    
    # 在页签,选择颜色
    driver.find_element_by_xpath('//ul[@data-property="颜色分类"]/li').click()
    
    
    • 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

    2.Web自动化项目框架搭建

    1.基于Pytest进行用例管理

    # 购物车登录
    def test_cart_login(browser):
        # 购物车登录
        # 打开淘宝购物车的登陆页面
        browser.get("https://cart.taobao.com/cart.htm")
    
        # 定位到账户名文本框
        browser.find_element('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码
        browser.find_element('id','fm-login-password').send_keys('xxx')
    
        # 点击登陆按钮
        browser.find_element('xpath',"//div[@class='fm-btn']").click()
    
    """
    
    装饰器@pytest.hookimpl(hookwrapper=True)等价于@pytest.mark.hookwrapper的作用:
        a.可以获取测试用例的信息,比如用例函数的描述
        b.可以获取测试用例的结果,yield,返回一个result对象
    """
    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport():
        # 可以获取测试用例的执行结果,yield,返回一个result对象
        out = yield
        """
         从返回一个result对象(out)获取调用结果的测试报告,返回一个report对象
         report对象的属性
         包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、
         outcome(用例的执行结果:passed,failed)
        """
        report = out.get_result()
        # 仅仅获取用例call阶段的执行结果,不包含setup和teardown
        if report.when == 'call':
            # 获取用例call执行结果为结果为失败的情况
            xfail  = hasattr(report,"wasfail")
            if(report.skipped and xfail) or (report.failed and not xfail):
                # 添加allure报告截图
                with allure.step("添加失败截图。。"):
                    # 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名 、 文件类型
                    allure.attach(driver.get_screenshot_as_png(),"失败截图",allure.attachment_type.PNG)
    
    import os
    
    import pytest
    
    
    def run():
        pytest.main(['-v','--alluredir','./result','--clean-alluredir','--allure-no-capture'])
        os.system('allure generate ./result -o ./report_allure/ --clean')
    
    if __name__ == '__main__':
        run()
    
    • 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

    2.关键字驱动

    # 所谓的关键字驱动,本质就是封装函数
    # 自动化测试中,封装的目的:拆分测试数据和重复的行为代码,增加可维护性和复用性
    # 定义关键字驱动类/工具类/基类
    from selenium import webdriver
    
    
    class WebKeys:
        # 构造方法,用于接收driver对象
        def __init__(self,driver):
            self.driver = driver
            # 编代码用,写完删掉
            # self.driver = webdriver.Chrome()
    
    
        # 打开浏览器
        def open(self,url):
            self.driver.get(url)
    
        # 元素定位
        def locator(self,name,value):
            """
    
            :param name: 元素定位的方式
            :param value: 元素定位的路径
            :return:
            """
            el = self.driver.find_element(name,value)
            # 将定位的元素框出来
            self.locate_station(el)
            return el
    
        # 显示定位的地方,方便确认定位的位置
        def locate_station(self,element):
            self.driver.execute_script(
                "arguments[0].setAttribute('style',arguments[1]);",
                element,
                "border: 2px solid green" #边框,green绿色
            )
    # 购物车登录
    import pytest
    
    # 跳过用例
    from class36.p03.key_world.keyword import WebKeys
    
    
    @pytest.mark.skip
    def test_cart_login(browser):
        # 购物车登录
        # 打开淘宝购物车的登陆页面
        browser.get("https://cart.taobao.com/cart.htm")
    
        # 定位到账户名文本框
        browser.find_element('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码
        browser.find_element('id','fm-login-password').send_keys('xxx')
    
        # 点击登陆按钮
        browser.find_element('xpath',"//div[@class='fm-btn']").click()
    
    # 使用关键字驱动模式实现购物车登录
    def test_case_login2(browser):
        # 初始化工具类,传递浏览器对象
        wk = WebKeys(browser)
        wk.open("https://cart.taobao.com/cart.htm")
        # 定位到账户名文本框
        wk.locator('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码框
        wk.locator('id','fm-login-password').send_keys('xxx')
        # 点击方式
        wk.locator('xpath',"//div[@class='fm-btn']").click()
    
    import os
    from time import sleep
    
    import allure
    import pytest
    
    # 每个用例如果引用了这个fixture,都会在用例执行前执行一下这个fixture
    from selenium import webdriver
    
    
    @pytest.fixture(scope='function')
    def browser():
        """
        全局定义浏览器驱动,方便下面的hook函数引用driver
        :return:
        """
        global driver
        os.popen("d:/chrome.bat")
        sleep(3)
    
        # 加载浏览器驱动
        options = webdriver.ChromeOptions()
        options.debugger_address = '127.0.0.1:9222'
        driver = webdriver.Chrome(options=options)
        sleep(2)
    
        # 隐式等待10秒
        driver.implicitly_wait(10)
    
        """
        yield之前的代码是用例前置
        yield之后的代码是用例后置
        """
        yield driver
        # 浏览器退出
        """
            这种debug模式,下面的方法无法退出浏览器
            driver.quit()
            driver.close()
        """
        # 通过命令杀死进程
        os.system('taskkill /im chromedriver.exe /F')
        os.system('taskkill /im chrome.exe /F')
    
    """
    
    装饰器@pytest.hookimpl(hookwrapper=True)等价于@pytest.mark.hookwrapper的作用:
        a.可以获取测试用例的信息,比如用例函数的描述
        b.可以获取测试用例的结果,yield,返回一个result对象
    """
    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport():
        # 可以获取测试用例的执行结果,yield,返回一个result对象
        out = yield
        """
         从返回一个result对象(out)获取调用结果的测试报告,返回一个report对象
         report对象的属性
         包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、
         outcome(用例的执行结果:passed,failed)
        """
        report = out.get_result()
        # 仅仅获取用例call阶段的执行结果,不包含setup和teardown
        if report.when == 'call':
            # 获取用例call执行结果为结果为失败的情况
            xfail  = hasattr(report,"wasfail")
            if(report.skipped and xfail) or (report.failed and not xfail):
                # 添加allure报告截图
                with allure.step("添加失败截图。。"):
                    # 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名 、 文件类型
                    allure.attach(driver.get_screenshot_as_png(),"失败截图",allure.attachment_type.PNG)
    import os
    
    import pytest
    
    
    def run():
        pytest.main(['-v','--alluredir','./result','--clean-alluredir','--allure-no-capture'])
        os.system('allure generate ./result -o ./report_allure/ --clean')
    
    if __name__ == '__main__':
        run()
    
    • 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

    3.PO模式

    # PO模式,关键字驱动模式的升级版
    # 以每个网页为单位,进行关键字的封装,也就是通常所说的页面对象模型
    # 定义关键字驱动类/工具类/基类
    from selenium import webdriver
    
    
    class WebKeys:
        # 构造方法,用于接收driver对象
        def __init__(self,driver):
            self.driver = driver
            # 编代码用,写完删掉
            # self.driver = webdriver.Chrome()
    
    
        # 打开浏览器
        def open(self,url):
            self.driver.get(url)
    
        # 元素定位
        def locator(self,name,value):
            """
    
            :param name: 元素定位的方式
            :param value: 元素定位的路径
            :return:
            """
            el = self.driver.find_element(name,value)
            # 将定位的元素框出来
            self.locate_station(el)
            return el
    
        # 显示定位的地方,方便确认定位的位置
        def locate_station(self,element):
            self.driver.execute_script(
                "arguments[0].setAttribute('style',arguments[1]);",
                element,
                "border: 2px solid green" #边框,green绿色
            )
    # 以页面为单位,封装常用的行为操作代码和元素定位代码
    from class36.p04.key_world.keyword import WebKeys
    
    
    class CatLoginPage(WebKeys):
        #登录操作
        def login(self,username,password):
            self.open("https://cart.taobao.com/cart.htm")
            # 定位到账户名文本框
            self.locator('id', 'fm-login-id').send_keys(username)
            # 定位到密码框
            self.locator('id', 'fm-login-password').send_keys(password)
            # 点击方式
            self.locator('xpath', "//div[@class='fm-btn']").click()
    # 购物车登录
    import pytest
    
    # 跳过用例
    from class36.p04.key_world.keyword import WebKeys
    from class36.p04.page.cartLogin_page import CatLoginPage
    
    
    @pytest.mark.skip
    def test_cart_login(browser):
        # 购物车登录
        # 打开淘宝购物车的登陆页面
        browser.get("https://cart.taobao.com/cart.htm")
    
        # 定位到账户名文本框
        browser.find_element('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码
        browser.find_element('id','fm-login-password').send_keys('xxx')
    
        # 点击登陆按钮
        browser.find_element('xpath',"//div[@class='fm-btn']").click()
    
    # 使用关键字驱动模式实现购物车登录
    @pytest.mark.skip
    def test_case_login2(browser):
        # 初始化工具类,传递浏览器对象
        wk = WebKeys(browser)
        wk.open("https://cart.taobao.com/cart.htm")
        # 定位到账户名文本框
        wk.locator('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码框
        wk.locator('id','fm-login-password').send_keys('xxx')
        # 点击方式
        wk.locator('xpath',"//div[@class='fm-btn']").click()
    
    # 使用PO模式实现购物车登录
    def test_case_login3(browser):
        # 初始化页面对象
        cartLogin = CatLoginPage(browser)
        cartLogin.login('云纱璃英','xxx')
    
    import os
    from time import sleep
    
    import allure
    import pytest
    
    # 每个用例如果引用了这个fixture,都会在用例执行前执行一下这个fixture
    from selenium import webdriver
    
    
    @pytest.fixture(scope='function')
    def browser():
        """
        全局定义浏览器驱动,方便下面的hook函数引用driver
        :return:
        """
        global driver
        os.popen("d:/chrome.bat")
        sleep(3)
    
        # 加载浏览器驱动
        options = webdriver.ChromeOptions()
        options.debugger_address = '127.0.0.1:9222'
        driver = webdriver.Chrome(options=options)
        sleep(2)
    
        # 隐式等待10秒
        driver.implicitly_wait(10)
    
        """
        yield之前的代码是用例前置
        yield之后的代码是用例后置
        """
        yield driver
        # 浏览器退出
        """
            这种debug模式,下面的方法无法退出浏览器
            driver.quit()
            driver.close()
        """
        # 通过命令杀死进程
        os.system('taskkill /im chromedriver.exe /F')
        os.system('taskkill /im chrome.exe /F')
    
    """
    
    装饰器@pytest.hookimpl(hookwrapper=True)等价于@pytest.mark.hookwrapper的作用:
        a.可以获取测试用例的信息,比如用例函数的描述
        b.可以获取测试用例的结果,yield,返回一个result对象
    """
    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport():
        # 可以获取测试用例的执行结果,yield,返回一个result对象
        out = yield
        """
         从返回一个result对象(out)获取调用结果的测试报告,返回一个report对象
         report对象的属性
         包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、
         outcome(用例的执行结果:passed,failed)
        """
        report = out.get_result()
        # 仅仅获取用例call阶段的执行结果,不包含setup和teardown
        if report.when == 'call':
            # 获取用例call执行结果为结果为失败的情况
            xfail  = hasattr(report,"wasfail")
            if(report.skipped and xfail) or (report.failed and not xfail):
                # 添加allure报告截图
                with allure.step("添加失败截图。。"):
                    # 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名 、 文件类型
                    allure.attach(driver.get_screenshot_as_png(),"失败截图",allure.attachment_type.PNG)
    
    import os
    
    import pytest
    
    
    def run():
        pytest.main(['-v','--alluredir','./result','--clean-alluredir','--allure-no-capture'])
        os.system('allure generate ./result -o ./report_allure/ --clean')
    
    if __name__ == '__main__':
        run()
    
    • 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
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175

    4.PO模式优化,元素定位分离

    #长流程复杂业务,页面元素封装界定不清晰以页面为单位,存储页面元素定位代码
    # 定义关键字驱动类/工具类/基类
    from selenium import webdriver
    
    
    class WebKeys:
        # 构造方法,用于接收driver对象
        def __init__(self,driver):
            self.driver = driver
            # 编代码用,写完删掉
            # self.driver = webdriver.Chrome()
    
    
        # 打开浏览器
        def open(self,url):
            self.driver.get(url)
    
        # 元素定位
        def locator(self,name,value):
            """
    
            :param name: 元素定位的方式
            :param value: 元素定位的路径
            :return:
            """
            el = self.driver.find_element(name,value)
            # 将定位的元素框出来
            self.locate_station(el)
            return el
    
        # 显示定位的地方,方便确认定位的位置
        def locate_station(self,element):
            self.driver.execute_script(
                "arguments[0].setAttribute('style',arguments[1]);",
                element,
                "border: 2px solid green" #边框,green绿色
            )
    
    """
    淘宝首页登录
    https://login.taobao.com/
    page_indexLogin
    """
    
    # 用户名
    page_indexLogin_user = ['id','fm-login-id']
    
    # 密码
    page_indexLogin_pwd = ['id','fm-login-password']
    
    # 登录按钮
    page_indexLogin_loginBtn = ['xpath', "//div[@class='fm-btn']"]
    
    from class36.p05.key_world.keyword import WebKeys
    from class36.p05.page import allPages
    
    
    class CatLoginPage(WebKeys):
        #登录操作
        def login(self,username,password):
            self.open("https://cart.taobao.com/cart.htm")
            # 定位到账户名文本框
            # self.locator(allPages.page_indexLogin_user[0],allPages.page_indexLogin_user[1]).send_keys(username)
            self.locator(*allPages.page_indexLogin_user).send_keys(username)
            # 定位到密码框
            self.locator(*allPages.page_indexLogin_pwd).send_keys(password)
            # 点击方式
            self.locator(*allPages.page_indexLogin_loginBtn).click()
    
    # 购物车登录
    import pytest
    
    # 跳过用例
    from class36.p05.key_world.keyword import WebKeys
    from class36.p05.page.cartLogin_page import CatLoginPage
    
    
    @pytest.mark.skip
    def test_cart_login(browser):
        # 购物车登录
        # 打开淘宝购物车的登陆页面
        browser.get("https://cart.taobao.com/cart.htm")
    
        # 定位到账户名文本框
        browser.find_element('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码
        browser.find_element('id','fm-login-password').send_keys('xxx')
    
        # 点击登陆按钮
        browser.find_element('xpath',"//div[@class='fm-btn']").click()
    
    # 使用关键字驱动模式实现购物车登录
    @pytest.mark.skip
    def test_case_login2(browser):
        # 初始化工具类,传递浏览器对象
        wk = WebKeys(browser)
        wk.open("https://cart.taobao.com/cart.htm")
        # 定位到账户名文本框
        wk.locator('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码框
        wk.locator('id','fm-login-password').send_keys('xxx')
        # 点击方式
        wk.locator('xpath',"//div[@class='fm-btn']").click()
    
    # 使用PO模式实现购物车登录
    def test_case_login3(browser):
        # 初始化页面对象
        cartLogin = CatLoginPage(browser)
        cartLogin.login('云纱璃英','xxx')
    
    import os
    from time import sleep
    
    import allure
    import pytest
    
    # 每个用例如果引用了这个fixture,都会在用例执行前执行一下这个fixture
    from selenium import webdriver
    
    
    @pytest.fixture(scope='function')
    def browser():
        """
        全局定义浏览器驱动,方便下面的hook函数引用driver
        :return:
        """
        global driver
        os.popen("d:/chrome.bat")
        sleep(3)
    
        # 加载浏览器驱动
        options = webdriver.ChromeOptions()
        options.debugger_address = '127.0.0.1:9222'
        driver = webdriver.Chrome(options=options)
        sleep(2)
    
        # 隐式等待10秒
        driver.implicitly_wait(10)
    
        """
        yield之前的代码是用例前置
        yield之后的代码是用例后置
        """
        yield driver
        # 浏览器退出
        """
            这种debug模式,下面的方法无法退出浏览器
            driver.quit()
            driver.close()
        """
        # 通过命令杀死进程
        os.system('taskkill /im chromedriver.exe /F')
        os.system('taskkill /im chrome.exe /F')
    
    """
    
    装饰器@pytest.hookimpl(hookwrapper=True)等价于@pytest.mark.hookwrapper的作用:
        a.可以获取测试用例的信息,比如用例函数的描述
        b.可以获取测试用例的结果,yield,返回一个result对象
    """
    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport():
        # 可以获取测试用例的执行结果,yield,返回一个result对象
        out = yield
        """
         从返回一个result对象(out)获取调用结果的测试报告,返回一个report对象
         report对象的属性
         包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、
         outcome(用例的执行结果:passed,failed)
        """
        report = out.get_result()
        # 仅仅获取用例call阶段的执行结果,不包含setup和teardown
        if report.when == 'call':
            # 获取用例call执行结果为结果为失败的情况
            xfail  = hasattr(report,"wasfail")
            if(report.skipped and xfail) or (report.failed and not xfail):
                # 添加allure报告截图
                with allure.step("添加失败截图。。"):
                    # 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名 、 文件类型
                    allure.attach(driver.get_screenshot_as_png(),"失败截图",allure.attachment_type.PNG)
    
    import os
    
    import pytest
    
    
    def run():
        pytest.main(['-v','--alluredir','./result','--clean-alluredir','--allure-no-capture'])
        os.system('allure generate ./result -o ./report_allure/ --clean')
    
    if __name__ == '__main__':
        run()
    
    • 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
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192

    5.PO模式优化,流程复用和流程备注

    # 定义关键字驱动类/工具类/基类
    from selenium import webdriver
    
    
    class WebKeys:
        # 构造方法,用于接收driver对象
        def __init__(self,driver):
            self.driver = driver
            # 编代码用,写完删掉
            # self.driver = webdriver.Chrome()
    
    
        # 打开浏览器
        def open(self,url):
            self.driver.get(url)
    
        # 元素定位
        def locator(self,name,value):
            """
    
            :param name: 元素定位的方式
            :param value: 元素定位的路径
            :return:
            """
            el = self.driver.find_element(name,value)
            # 将定位的元素框出来
            self.locate_station(el)
            return el
    
        # 显示定位的地方,方便确认定位的位置
        def locate_station(self,element):
            self.driver.execute_script(
                "arguments[0].setAttribute('style',arguments[1]);",
                element,
                "border: 2px solid green" #边框,green绿色
            )
    
        # 获取title,获取网页标题栏
        def get_title(self):
            return self.driver.title
    
    
    """
    淘宝首页登录
    https://login.taobao.com/
    page_indexLogin
    """
    
    # 用户名
    page_indexLogin_user = ['id','fm-login-id']
    
    # 密码
    page_indexLogin_pwd = ['id','fm-login-password']
    
    # 登录按钮
    page_indexLogin_loginBtn = ['xpath', "//div[@class='fm-btn']"]
    
    """
    购物车详情页
    https://cart.taobao.com/cart.htm
    page_cartDetail
    """
    # 全选按钮
    page_cartDetail_selectAll = ["id","J_SelectAll1"]
    # 结算按钮
    page_cartDetail_payBtn = ["xpath","//div[@class='btn-area']"]
    # 提交订单按钮
    page_cartDetail_submitBtn = ["link text","提交订单"]
    # 删除按钮
    page_cartDetail_delBtn = ["link text","删除"]
    # 关闭按钮
    page_cartDetail_closeBtn = ["partial link text","闭"]
    # 确定按钮
    page_cartDetail_confirmBtn = ["partial link text","确"]
    # 颜色分类栏
    page_cartDetail_colorClum = "//p[@class='sku-line']"
    # SKU修改按钮
    page_cartDetail_modifyBtn = ["xpath","//span[text()='修改']"]
    # 颜色分类
    page_cartDetail_colors = ["xpath","//div[@class='sku-edit-content']/div/dl/dd/ul/li[2]"]
    # 颜色分类确认按钮
    page_cartDetail_colorsConfirmBtn = ["xpath","//div[@class='sku-edit-content']/div/p/a"]
    # 移入收藏夹
    page_cartDetail_favorites = ["link text","移入收藏夹"]
    # 单一商品信息栏
    page_cartDetail_singleGoodsClum = "//div[@class='order-content']"
    # 相似宝贝超链接
    page_cartDetail_similarGoodsLink = ["link text","相似宝贝"]
    # 翻页按钮
    # page_cartDetail_simlarGoddsNext = ["xpath","//a[@class='fss-navigator fss-next J_fs_next ']"]
    page_cartDetail_simlarGoddsNext = ["xpath","//a[contains(@class,'J_fs_next')]"]
    # 相似宝贝
    page_cartDetail_simlarGoods = ["xpath","//div[@class='find-similar-body']/div/div/div[2]"]
    
    from time import sleep
    
    import allure
    
    from class36.p06.key_world.keyword import WebKeys
    
    
    # 购车页面
    from class36.p06.page import allPages
    from class36.p06.page.cartLogin_page import CatLoginPage
    
    
    class CartPage(WebKeys):
        # 商品结算
        @allure.step("商品结算")
        def pay(self):
            # 在报告里展示代码路径,方便查找
            with allure.step("流程代码路径: %s" % __file__):
                pass
    
            # 复用登录流程
            loginPage = CatLoginPage(self.driver)
            loginPage.login('云纱璃英','xxx')
    
            with allure.step("点击全选按钮"):
                self.locator(*allPages.page_cartDetail_selectAll).click()
                sleep(1)
            with allure.step("点击结算按钮"):
                self.locator(*allPages.page_cartDetail_payBtn).click()
                sleep(1)
    # 以页面为单位,封装常用的行为操作代码和元素定位代码
    from time import sleep
    
    import allure
    
    from class36.p06.key_world.keyword import WebKeys
    from class36.p06.page import allPages
    
    
    class CatLoginPage(WebKeys):
        #登录操作
        @allure.step("登录")
        def login(self,username,password):
            # 在报告里展示代码路径,方便查找
            with allure.step("流程代码路径: %s"%__file__):
                pass
            with allure.step("打开网页")
                self.open("https://cart.taobao.com/cart.htm")
            with allure.step("输入账户"):
                # 定位到账户名文本框
                # self.locator(allPages.page_indexLogin_user[0],allPages.page_indexLogin_user[1]).send_keys(username)
                self.locator(*allPages.page_indexLogin_user).send_keys(username)
            with allure.step("输入密码"):
                # 定位到密码框
                self.locator(*allPages.page_indexLogin_pwd).send_keys(password)
            with allure.step("点击登录"):
                # 点击方式
                self.locator(*allPages.page_indexLogin_loginBtn).click()
    
            sleep(2)
            # 登录后的结果检查
            result = self.get_title()
            expect = "购物车"
            with allure.step("结果检查:(预期){1} in 实际{0}".format(result,expect)):
                assert expect in result
    
    # 购物车登录
    import pytest
    
    # 跳过用例
    from class36.p06.key_world.keyword import WebKeys
    from class36.p06.page.cartLogin_page import CatLoginPage
    from class36.p06.page.cart_page import CartPage
    
    
    @pytest.mark.skip
    def test_cart_login(browser):
        # 购物车登录
        # 打开淘宝购物车的登陆页面
        browser.get("https://cart.taobao.com/cart.htm")
    
        # 定位到账户名文本框
        browser.find_element('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码
        browser.find_element('id','fm-login-password').send_keys('xxx')
    
        # 点击登陆按钮
        browser.find_element('xpath',"//div[@class='fm-btn']").click()
    
    # 使用关键字驱动模式实现购物车登录
    @pytest.mark.skip
    def test_case_login2(browser):
        # 初始化工具类,传递浏览器对象
        wk = WebKeys(browser)
        wk.open("https://cart.taobao.com/cart.htm")
        # 定位到账户名文本框
        wk.locator('id','fm-login-id').send_keys('云纱璃英')
        # 定位到密码框
        wk.locator('id','fm-login-password').send_keys('xxx')
        # 点击方式
        wk.locator('xpath',"//div[@class='fm-btn']").click()
    
    # 使用PO模式实现购物车登录
    def test_case_login3(browser):
        # 初始化页面对象
        cartLogin = CatLoginPage(browser)
        cartLogin.login('云纱璃英','xxx')
    
    # 实现购物车的结算
    def test_case_pay(browser):
        # 初始化购物车页面对象
        cartPage = CartPage(browser)
        cartPage.pay()
    
    import os
    from time import sleep
    
    import allure
    import pytest
    
    # 每个用例如果引用了这个fixture,都会在用例执行前执行一下这个fixture
    from selenium import webdriver
    
    
    @pytest.fixture(scope='function')
    def browser():
        """
        全局定义浏览器驱动,方便下面的hook函数引用driver
        :return:
        """
        global driver
        os.popen("d:/chrome.bat")
        sleep(3)
    
        # 加载浏览器驱动
        options = webdriver.ChromeOptions()
        options.debugger_address = '127.0.0.1:9222'
        driver = webdriver.Chrome(options=options)
        sleep(2)
    
        # 隐式等待10秒
        driver.implicitly_wait(10)
    
        """
        yield之前的代码是用例前置
        yield之后的代码是用例后置
        """
        yield driver
        # 浏览器退出
        """
            这种debug模式,下面的方法无法退出浏览器
            driver.quit()
            driver.close()
        """
        # 通过命令杀死进程
        os.system('taskkill /im chromedriver.exe /F')
        os.system('taskkill /im chrome.exe /F')
    
    """
    
    装饰器@pytest.hookimpl(hookwrapper=True)等价于@pytest.mark.hookwrapper的作用:
        a.可以获取测试用例的信息,比如用例函数的描述
        b.可以获取测试用例的结果,yield,返回一个result对象
    """
    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport():
        # 可以获取测试用例的执行结果,yield,返回一个result对象
        out = yield
        """
         从返回一个result对象(out)获取调用结果的测试报告,返回一个report对象
         report对象的属性
         包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、
         outcome(用例的执行结果:passed,failed)
        """
        report = out.get_result()
        # 仅仅获取用例call阶段的执行结果,不包含setup和teardown
        if report.when == 'call':
            # 获取用例call执行结果为结果为失败的情况
            xfail  = hasattr(report,"wasfail")
            if(report.skipped and xfail) or (report.failed and not xfail):
                # 添加allure报告截图
                with allure.step("添加失败截图。。"):
                    # 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名 、 文件类型
                    allure.attach(driver.get_screenshot_as_png(),"失败截图",allure.attachment_type.PNG)
    
    import os
    
    import pytest
    
    
    def run():
        pytest.main(['-v','--alluredir','./result','--clean-alluredir','--allure-no-capture'])
        os.system('allure generate ./result -o ./report_allure/ --clean')
    
    if __name__ == '__main__':
        run()
    
    
    • 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
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
  • 相关阅读:
    Java使用正则表达式-验证邮箱
    MMDetection3D框架环境配置
    基于MQ的分布式事务实现方案
    掌握Linux常用命令,扫平面试需求障碍
    Alibaba架构师纯手工打造神仙级“2022版Java面试手册”
    山西电力市场日前价格预测【2023-10-24】
    C++中的is_same_v和conditional_t
    nodejs+vue宁夏旅游景点客流量数据分析
    动能方案 | 15693协议的读卡器应用 DP1363F 替代RC663
    Three.js——骨骼动画
  • 原文地址:https://blog.csdn.net/BlackEnn/article/details/126077511