前情提要:

通用方法和特定方法

比如:查找某个元素的方法 def find(locator),只要传入locator,就可以调用该函数,可以通用的---一般放在common中,例如:selenium_handler.py

对于登录操作,需要先定位元素,每个项目中定位元素的方式可能是不一样的,所以对于登录操作,应该是项目的特定方法.

 80\46min

1.basepage的实现

 1).项目架构:

------selenium_handler.py放在common中,在selenium_handler实现封装

-------middleware中新建pages 包(表示:页面操作)  ----比如:登录操作,就属于页面的行为;登录页面有:免费注册、忘记密码、联系我们等操作行为

        在pages中可以有login.py操作

 

2).实现login.py登录操作的封装

将前面的测试用例test_login中登录部分的代码直接拿过来进行封装;

 -----用户名、密码进行参数化。

 -----driver对象在很多页面都需要用到,所以定义为类属性,方便调用

class LoginPage:
    """登录"""

    #初始化driver
    def __init__(self,driver):
        self.driver = driver

    def login(self,username,password):
        # 访问登录页面
        url = "http://120.78.128.25:8765/Index/login.html"
        self.driver.get(url)

        # 元素定位+元素操作,输入用户名和密码,点击登录进行提交
        self.driver.find_element_by_name("phone").send_keys(username)
        self.driver.find_element_by_name("password").send_keys(password)
        self.driver.find_element_by_class_name("btn-special").click()

架构:

 

 

 

login.py封装完成,在测试用例中test_login.py中如何去调用呢------在test_login.py中直接调用即可。

import pytest
from middware.handler import HandlerMiddle
from middware.pages.login import LoginPage

#获取excel中login数据
data = HandlerMiddle.excel.read_data("login")

class TestLogin():
    """登录功能的测试类"""
    @pytest.mark.smoke
    @pytest.mark.error
    @pytest.mark.parametrize("test_info",data)
    def test_login_error(self,test_info,driver):
        """登录失败测试步骤
        1.打开浏览器
        2.访问登录页面
        3.元素定位+元素操作,输入用户名和密码,点击登录
        4.通过获取页面内容得到实际结果,进行断言
        :return:
        """

        #访问登录页面
        LoginPage(driver).login(username=eval(test_info["data"])["username"],
                                password=eval(test_info["data"])["password"])


        #通过获取页面内容得到实际结果,进行断言
        #实际结果是在页面上的提示,再次进行定位
        actual_result = driver.find_element_by_class_name("form-error-info").text
        expected_result = test_info["expected_result"]
        #断言
        assert actual_result in expected_result

运行run.py, test_login.py中的方法test_login_error()中的driver去conftest文件中找fixture中的函数名(driver),访问登录页面调用LoginPage(driver),到此逻辑基本理顺了。

 

总结:

1)登录操作封装成类,初始化LoginPage()对象---->测试代码和页面操作分开。

    -----这么做的好处:前端工程师修改页面,就不需要修改test_login.py测试用例。

                                   测试逻辑改了,那么LoginPage是不需要修改的。

 

 2)pytest测试框架的特性

①用例标记Mark

  --pytest.ini文件,注册标签名

  --打标签pytest.mark.tagname     测试类或者测试方法上

  --运行 pytest -m "tagname"     标记的组合 and 、or、 not (tagnameA ang not tagnameB)

②断言  直接用python的内置关键字 assert

③测试报告 --html =report.html

④使用脚本方式运算:pytest.main(["--html={}report.html".format(ts), "-m error"])

⑤测试顺序:从上到下

⑥数据驱动:pytest.mark.parametrize("test_info",data)

                      def test_login(self,test_info):

        pass

    数据驱动注意事项: 使用pytest.mark.parametrize("test_info",data)时,pytest与unittest不兼容:即使用pytest的数据驱动,测试类不能继承unittest.TestCase;用unittest框架就继承,且使用ddt数据驱动。

①测试夹具---生成器generator(含有yield关键字)

---本质是:普通函数

---@pytest.fixture()申明这是一个测试夹具

---把函数中的return改为yield: yield前:前置条件;yield后:后置清理

 

3)pytest与unittest共用:

 unittest编写用例:

  ---ddt、setUp、testDown、self.assertTrue()

pytest运行用例:

---自动收集、用例筛选用例、测试报告、测试插件

 

 4)为什么用pytest?有什么优势;unittest有什么优势?

① unittest是Python的标准库,pytest是第三方库 (unittest不需要安装,pytest需要安装)

   ---标准库不存在 和Python版本不兼容的问题

②pytest更加智能,上面2)所述