zoukankan      html  css  js  c++  java
  • pytest

    pytest和unittest区别:

    1、表达用例:
    unittest: 定义一个测试类,继承unittest.TestCase
    pytest: 类/函数

    2、断言的表达:
    unittest: self.assertXXXX()
    pytest: assert 表达式(结果为True-断言成功,否则-断言失败!) 逻辑/成员/比较/函数返回值

    3、收集用例:
    unittest: TestLoader类+TestSuite类,discover收集用例
    pytest: 自动收集用例

    4、fixture: 前置后置。
    unittest: setup&teardown setupClass&teardownClass --- 固定的名称
    pytest: function(用例) -> class(测试类) -> Module(.py) -> Session(会话)

    5、插件:
    unittest: 无
    pytest: 700+
    http://plugincompat.herokuapp.com/
    html插件
    allure报告
    重运行
    1、报告
    2、用例收集
    3、执行用例
    4、断言
    5、数据驱动
    6、重新运行失败的用例
    7、筛选
    8、前置后置的处理。
    9、加载测试用例

    pytest收集测试用例的规则:
    1、默认从当前目录中搜集测试用例,即在哪个目录下运行pytest命令,则从哪个目录当中搜索;
    2、搜索规则符合以下标准的文件才会去确认是否有用例:
    1)符合命名规则 test_*.py 或者 *_test.py 的文件 .py文件
    2)以test_开头的函数名;
    3)以Test开头的测试类(没有__init__函数)当中,以test_开头的函数

    执行顺序:
    1.文件名称顺序 -ACSII排序
    2.哪个文件先识别哪个用例先执行
    3.文件内部:代码的先后顺序




    对测试用例打标签。在运行测试用例的时候,可根据标签名来过滤要运行的用例。
    使用方法:
    1、注册标签名
    2、在测试用例/测试类前面加上:@pytest.mark.标记名

    注册方式:
    1、创建pytest.ini文件,在文件中按如下形式添加标签名:
    [pytest]
    markers =
    slow: marks tests as slow (deselect with '-m "not slow"')
    serial
    demo
    smoke
    注:冒号之后是可选的描述信息

    2、运行的时候,只运行打了标记的用例。
    pytest.main(["-m","标签名","-s","-v"])
    unittest.main()
    打标记范围:测试用例、测试类、模块文件

    使用方法-1:
    在测试用例/测试类前面加上:@pytest.mark.标记名,如:@pytest.mark.slow

    可在一个用例上打多个标签。多次使用@pytest.mark.标签名即可。
    示例:
    @pytest.mark.smoke
    @pytest.mark.demo
    def test_demo():
    print(“我是示例啦!!!”)


    使用方法-2:
    在测试类里,使用以下申明(测试类下,所有用例都被打上该标签):
    class TestClass(object):
    pytestmark = pytest.mark.已注册标签名
    pytestmark = [pytest.mark.标签1, pytest.mark.标签2] # 多标签模式


    在 模块文件里,同理(py文件下,所有测试函数和测试类里的测试函数,都有该标签):
    import pytest
    pytestmark = pytest.mark.webtest
    pytestmark = [pytest.mark.标签1, pytest.mark.标签2] # 多标签模式
    
    

     



    事例:
    
    pytest.ini
    
    [pytest]
    markers =
        demo: just for demo show
        nmb
        smoke
    
    test_demo.py
    
    import pytest
    
    # pytestmark = pytest.mark.nmb
    
    def aaa():
        pass
    
    
    # @pytest.mark.nmb
    class TestAA:
    
        # pytestmark = pytest.mark.nmb
    
        def test_bbb(self):
            print("bbbb")
            self.bbb()
            assert "hello" == "World!"
    
        @pytest.mark.demo
        def test_hello_pytest(self):
            print("hello,pytest!!!")
    
        def bbb(self):
            print("*************88")
    
    
    
    @pytest.mark.demo
    def test_aaa():
        print("aaaaaaa")
        assert True
    
    test_nmb.py
    
    import pytest
    
    
    @pytest.mark.demo
    def test_nmb_py25():
        print("python25!")
    
    run.py
    
    import pytest
    
    # pytest.main(["-s","-m","demo","-v"])
    pytest.main()  # 收集到的用例 ,全部运行。
        
     定义:1、怎么知道函数它是一个前置&后置?
               在函数前面 :@pytest.fixture
               @pytest.fixture
               def init():
                  pass
    
               2、怎么区分前置和后置? yield -- 前后置的分隔分
               @pytest.fixture
               def init():
                  driver = webdriver.Chrome()
                  driver.get("http://www.baidu.com")
                  yield
                  driver.quit()
    
               3、作用域是什么?测试函数/类/模块/会话?  @pytest.fixture(scope=?) 
            四个级别的前置后置:
    function: 默认值。
    -- unittest当中setup和teardown。夹了测试用例。 默认是function的scope就是测试用例
    class:测试类。 --- unittest当中setupClass和teardownClass. 面包里夹的是测试类,每个class的test只运行一次 module: 模块。.py ---- 整个py文件。 厨房里找到的鸡蛋 -- 2片面包
    session:会话。
    --- 夹是你收集到的所有测试用例。 家里所有的鸡蛋 -- 2片面包 接口:前置: 连接数据库? 后置:关闭连接 4、返回前置当中的变量:yield 返回值1 返回值2 调用: 4、测试用例当中,如何调用这个前置后置? 在测试用例/类的前面: @pytest.mark.usefixture("定义的fixture名称") 执行了init对应的前置动作 5、接收返回值的方式: 将fixture的函数名称,作为用例的参数 用例的参数 = 返回值 测试用例的参数:1、数据驱动;2、fixture的返回值。 如果你要使用fixture的返回值,那一定要传参。可以不用@pytest.mark.usefixtures 如果fixture没有返回值,测试要使用,必须申明:@pytest.mark.usefixtures

    # 3、如何应用在测试用例上? - 测试用例当中,主动引用需要的fixture。
    1、通过装饰器直接使用:
    用例不需要使用fixture的返回值:
    @pytest.mark.usefixture("fixture的函数名称")

    用例需要使用fixture的返回值:
    第一步:测试用例/类 @pytest.mark.usefixture("fixture的函数名称")
    第二步:将fixture的函数名称 作为 测试用例的 参数。 fixture函数名称 = fixture函数的返回值。

    2、可以使用多个前置后置。但是不能冲突 。比如:打开2次浏览器。


    3、session级别的会话 - autouse可以设置为True

    4、pytest用例的执行顺序:文件名称的顺序 - 测试用例的代码顺序

    # 我有许多的不同的前置 后置,怎么办?
      1)层级的conftest.py
      2)有些前置后置,只有自己的测试用例要用。直接在测试用例文件中定义fixture.

    共享:conftest.py ---名称固定。专 1)专门用来存放fixture. 2)作用域(哪些范围内的用例都可以使用):conftest.py所在的文件夹内的用例都可以使用 3)用例文件当中不需要引入,直接调用fixture名称就可以了。 4)可以在不同的层级,创建conftest.py

    示例:
    @pytest.fixture #默认scope为function
    def myfixture():
    driver = webdriver.Chrome() #测试用例执行之前,执行的准备工作
    yield driver #将driver作为返回值。在测试用例中需要使用driver
    driver.close() #测试用例执行完成之后,要执行的清理操作
    driver.quit() #测试用例执行完成之后,要执行的清理操作

    事例:

    test_web.py文件
    
    import pytest
    from selenium import webdriver
    
    
    
    
    @pytest.fixture(scope="class")#修改为class类
    def mycc():
        print("======我是类级别的前置!!,开始======")
        yield
        print("======我是类级别的后置,再见======")
    
    
    
    
    # 测试用例
    # def test_baidu():
    #     print("1111111111111111111111111")
    #
    # @pytest.mark.usefixtures("init")
    # def test_taobao():
    #     print("taobao.......")
    
    
    # @pytest.mark.usefixtures("init")  # 夹的是测试函数 #
    @pytest.mark.usefixtures("mycc")  # 夹的是测试类
    class TestAA:
    
    
        def test_aa(self):
            print("***********  test_aa  ***********")
    
        # @pytest.mark.usefixtures("init")
        def test_bb(self):
            print("***********test_bb***********")
    
        def test_baidu(self,init):  # init = driver对象 # init = (driver,True)
            print("baidu.......")
            init.find_element_by_id("kw").send_keys("nmb")
    
        # 假设这个类下面,有10个用例,只有1个用例的前置后置不太一样,你会怎么处理?
        # 拎取出来当成函数。
    

    conftest.py文件

    import pytest from selenium import webdriver # 定义fixture @pytest.fixture() # pytest就能识别它为一个前置后置 def init(): # 前置 print("****我是函数别的前置!!,开始****") driver = webdriver.Chrome() driver.get("http://www.baidu.com") # yield driver,True # 返回driver对象,可以返回多个对象 yield driver # 后置 print("****我是函数别的后置!!,结束****") driver.quit() #conftest.py 共享的范围:它爸爸下的所有测试用例。 #定义公共的fixture,多个测试类中都可以调用。 #pytest提供了conftest.py文件,可以将fixture定义在此文件中。 #运行测试用例时,不需要去导入这个文件,会自动去查找conftest.py文件,然后去找到对应的fixture。




    输出:

    ======我是类级别的前置!!,开始======
    PASSED [ 33%]*********** test_aa ***********
    PASSED [ 66%]***********test_bb***********
    ****我是函数别的前置!!,开始****
    PASSED [100%]baidu.......
    ****我是函数别的后置!!,结束****
    ======我是类级别的后置,再见======

     
    
    
    pytest的参数化:
        在测试用例的前面加上:
        @pytest.mark.parametrize("参数名",列表数据)
        参数名:用来接收每一项数据,并作为测试用例的参数。
        列表数据:一组测试数据。
    
        @pytest.mark.parametrize("参数1,参数2",[(数据1,数据2),(数据1,数据2)])
        示例:
           @pytest.mark.parametrize("a,b,c",[(1,3,4),(10,35,45),(22.22,22.22,44.44)])
           def test_add(a,b,c):
                res = a + b
                assert res == c
    
    
        组合参数化:多组参数,依次组合。
        使用多个@pytest.mark.parametrize
        
        示例:用例有4个:0,2/0,3/1,2/1,3  迪卡尔积
        @pytest.mark.parametrize("x", [0, 1])
        @pytest.mark.parametrize("y", [2, 3])
        def test_foo(x, y):
            pass
    
    
    pytest插件,安装好了,有的会带来额外的运行参数。
        重运行机制 - 针对的失败的用例/ 重运行几次?
           Pytest提供了失败重试机制:
            插件名称:rerunfailures
            安装方法:pip install pytest-rerunfailures
            重试方式:用例一旦失败了,马上重运行用例。
        
            使用方式:
            命令行参数形式:
            命令:pytest --reruns 重试次数
            比如:pytest --reruns 2 表示:运行失败的用例可以重新运行2次。
        
            命令:pytest --reruns 重试次数 --reruns-delay 次数之间的延时设置(单位:秒)
            Pytest --reruns 2 --reruns-delay 5
            表示失败的用例可以重新运行2次。第一次和第二次的间隔时间为5秒钟。
    
    
    
    html的测试报告:
    安装:pip install pytest-html
    
    命令:pytest --html=相对路径
    conftest.py
    
    # 测试用例级别
    
    import pytest
    from selenium import webdriver
    from web_basepage.TestDatas import Common_Datas as CD
    from web_basepage.PageObjects.login_page import LoginPage
    import logging
    from web_basepage.Common import logger
    
    @pytest.fixture
    def init_driver():
        """
        前置:打开浏览器,访问系统网址
        后置:退出浏览器。
        """
        logging.info("***** conftest.py共享的 init_driver 的前置  *****")
        driver = webdriver.Chrome()
        driver.get(CD.login_url)
        yield driver
        driver.quit()
        logging.info("***** conftest.py共享的 init_driver 的后置  *****")
    
    """
    前置:打开浏览器,访问系统网址 + 登陆系统
    后置:退出浏览器。
    """
    @pytest.fixture
    def init_login(init_driver): # init_driver代表的是它的返回值:driver
        LoginPage(init_driver).login(CD.user, CD.passwd)
        yield init_driver  # 返回driver对象。
        print("1111111111111")
    """
    init_driver的前置
    init_login的前置
    init_login的后置
    init_driver的后置
    
    假设:init_driver是class级,init_login是function级别?
          可以"继承"。
          init_driver是function级,init_login是function级别?
          可以互相调用。
          init_driver是function级,init_login是class级别?
          不可以。
    
    一个fixture,可以使用比它高的/与它同级的 fixture作为它的参数。 
    
       function,可以调用class,function,module,session.
       function最小单位。最后执行。其它的级别一定是比它先执行。
    
    
    进去:校门 -> 楼大门 -> 教室门
    出来:教室门 -> 楼大门 -> 校门
    """
    
    
    test.login.py
    
    from selenium import webdriver
    import logging
    from web_basepage.Common import logger
    
    from web_basepage.PageObjects.login_page import LoginPage
    from web_basepage.PageObjects.home_page import HomePage
    
    from web_basepage.TestDatas import Common_Datas as CD
    from web_basepage.TestDatas import login_datas as LD
    import pytest
    
    
    @pytest.fixture
    def init(init_driver):
        logging.info("***** login用例自己的 init 的前置  *****")
        lp = LoginPage(init_driver)
        yield init_driver,lp   #(driver对象,lp页面对象)
        logging.info("***** login用例自己的 init 的后置  *****")
    
    
    @pytest.mark.usefixtures("init")
    class TestLogin:
    
        # 正常场景 - 登陆成功。
        def test_login_success(self,init):
            logging.info("******* 登陆功能 - 正常场景用例:登陆成功 *******")
            # 调用登陆页面的。登陆行为。
            init[1].login(LD.success_data["user"], LD.success_data["passwd"])
            # 断言 - 首页当中,应该存在 退出元素。
            assert HomePage(init[0]).check_user_exist()
            # 断言2 - url地址  应当为 http://120.78.128.25:8765/Index/index
            assert init[0].current_url == LD.success_data["check_url"]
    
        #unpace  解包两层如:[(),()]
        # 异常用例 - 用户名为空/密码为空/用户名格式不正确
        # @ddt.data(*LD.wrong_datas)
        @pytest.mark.parametrize("case",LD.wrong_datas)#不需要解包、case名称用来接收一组数据,需要一致
        def test_login_failed_by_wrongData(self,case,init):
            logging.info("******* 登陆功能 - 异常场景用例:数据格式校验 - 用户名为空/密码为空/用户名格式不正确 *******")
            # 调用登陆页面的。登陆行为。
            init[1].login(case["user"], case["passwd"])
            # 断言 - 登陆页面 - 应当现提示信息:请输入手机号
            self.assertEqual(case["check"], init[1].get_error_msg())
    pytest.ini
    
    [pytest]
    markers=
        demo
    
    test.demo.py
    
    import pytest
    
    pytestmark = pytest.mark.demo#打标记
    
    def test_aa():
        print("11111111111111111111")
    
    class Testaa:
    
        def test_demo(self):
            print("demo")
    
        def test_bb(self):
            print("bb")
    
        def test_false(self):
            print("====== 我是失败的用例 +++=====")
            assert False
    
    main.py
    
    import pytest
    
    pytest.main(["-s","-v","-m","demo","--html=Outputs/report.html",
                 "--reruns","2","--reruns-delay","5"])
    #过滤demo用例,生成html报告,

      

    #如果test_login.py有返回值要用,直接传mySs,如: def test_login_failed_by_wrongData(self,case,init,mySs):
    #autouse=True, 除了session其它级别的不用开
    conftest.py
    @pytest.fixture(scope="session",autouse=True)
    def mySs():
        print("**** 我是session级别的fixture 前置 ****")
        yield True #如有返回值
        print("**** 我是session级别的fixture 后置 ****")
    
    test_demo.py
    import pytest
    
    def test_aa(mySs):
        print(mySs)
    
    
    输出:True
    
    conftest.py @pytest.fixture(scope
    ="session",autouse=True) def mySs(): print("**** 我是session级别的fixture 前置 ****") yield #无返回值 autouse自动执行了 print("**** 我是session级别的fixture 后置 ****" test_demo.py import pytest def test_aa(): print("11111111111111111111") 输出:11111111111111111111 conftest.py @pytest.fixture(scope="module") def myMo(): print("**** 我是module级别的fixture 前置 ****") yield print("**** 我是module级别的fixture 后置 ****") test_demo.py import pytest @pytest.mark.usefixtures("myMo") #在这个模块 再哪一行调用,它后面的才会生效,前面的不生效,一般使用不多, 如果要用一般是在模块的开始部位定义 def test_aa(): print("11111111111111111111") class Testaa: def test_demo(self): print("demo") def test_bb(self): print("bb")
  • 相关阅读:
    LeetCode 1672. 最富有客户的资产总量
    LeetCode 455. 分发饼干
    Linux上安装docker并设置免sudo权限与国内镜像源
    Java后端期末复习
    Windows 10 家庭版开启本地安全策略 关闭管理员权限提升
    C语言中两种交换变量值方法的速度测试
    jQuery动态生成元素无法绑定事件的解决办法
    JQuery绑定事件处理动态添加的元素
    Socket通信服务端和客户端总结
    js传函数指针
  • 原文地址:https://www.cnblogs.com/zcok168/p/13274224.html
Copyright © 2011-2022 走看看