1.0 python之pytest使用

1. Pytest介绍
   A. 与unittest对比?
     基于unittest之上的单元测试框架。
       1)自动发现测试模块和测试方法
       2) 断言使用assert+表达式即可
       3) 可以设置测试会话级、模块级、函数级的fixtures数据准备+清理工作;
        4) 有丰富的插件库,目前有600个以上。 ==allure
   B. 安装
   安装命令:pip install pytest
          安装html报告的插件:pip install pytest-html
          pytest插件地址:http://plugincompat.herokuapp.com/
    C. Pytest收集测试用例的规则
       1) 默认从当前目录中搜集用例,即在那个目录下运行pytest命令,则从那个目录当中搜索
       2) 搜索规则:
           a. 符合规则”test_*.py“或者”*_test.py“的文件
           b. 以"test_"开头的函数名
           c. 以Test开头的测试类(没有__init__函数)当中,以"test_"开头的函数名;
           d. 用例可能会有多层,包名无限制  

2. Pytest之mark功能:
    对测试用例打标签,在运行用例的时候,可根据标签名来过滤要运行的用例
    使用方法:
     1) 注册标签名
       注册步骤:
        1) 创建一个pytest.ini文件(建议:尽量放在项目目录下,其他位置也可以,pytest会从项目目录开始寻找),在文件中按照如下形式加标签名:
        [pytest]
        markers=
             slow:marks tests as slow(deselect with "not slow")
             smoke: test some important cases
             uaual: some cases tested often waste much time 
          注意:冒号之后是标签的描述信息
     2)  在测试用例/测试类前面加上: @pytest.mark.标记名
          ( 测试类上打的标记会被同样打在该测试类中的每一个方法,
           一个测试类或测试函数可以有多个标签)
     3) 根据用例标签筛选出指定用例并运行
            (参考:3. Pytest之命令运行功能 )
3. Pytest之命令运行功能
    1) 可以在用例目录下,新建一个py文件,内容如下:
        if __name__=="__main__":
           pytest.main()
           # 也可以下边这种方式
           pytest.main(["-s","-v"]) 
    2) dos命令窗口,进入到用例目录下,然后:执行用例会比pytest.mian()输出结果更详细
        python 命令敲入回车,也可执行用例
        pytest -s -v 命令敲入回车,执行用例会比pytest输出结果更详细
    3) 筛选用例进行执行
        a. 执行all标签的用例
           - 编辑器中(Pycharm): 
               if __name__=="__main__":
                  pytest.main(["-s","-v","-m","all"])
           - dos窗口中,命令行参数:
                  pytest -s -v -m all
        b. 执行多个标签的用例,如标签:all和test1和test2
           - 编辑器中(Pycharm): 
               if __name__=="__main__":
                  pytest.main(["-s","-v","-m","all or test1 or test2"])
           - dos窗口中,命令行参数:
                  pytest -s -v -m  "all or test1 or test2” 
    注意: pytest命令在那个目录执行,那就以此目录韦根目录,按照规则自行去搜索用例



4. Pytest之fixture功能
1) 前置后置共享
       a. 前置后置共享函数定义
          新建一个conftest.py文件,在测试用例目录下,在该文件当中,假如定义一个函数:init_def:
          
         @pytest.fixture(scope="function")
         def init_def():
             print("函数前置")
             yield
             print("函数后置")
         
         在 @pytest.fixture(scope="function"),
           scope=function则代表测试用例的前置后置(即setUp和tearDown函数)
           scope=class,代表测试类前置后置(即@classmethod装饰的setUpClass和tearDownClass函数);
           scope=module, 代表py模块的前置后置,在模块中调用时,如果在第一个用例前用了,那么该模块会用,如果非第一个模块使用,那么该前置后置的作用域则在该用例及其之后(在执行第一个用例前不执行前置;
           scope=session, 代表夹的是所有用例

(注意,如果@pytest.fixture()的参数除了scope,常用的还有
autouse : 代表无需调用,直接使用,如果是测试函数内部使用,则需要将该前后置函数名作为变量放到测试函数参数中,测试函数内部就可以直接使用了

       b. 前置后置函数的调用
          在测试类中,假设存在一个登录测试类:TestLogin,调用时,就在该测试类上方加入一行:  @pytest.mark.usefixtures("init_def"),即:
          使用@pytest.mark.usefixtures("init_def")装饰测试类TestLogin
       
       注意: 如果说前置后置中的变量,测试类的测试用例会用到,那么需要:
           a). 前置后置函数定义时,yiled 变量名
            
               @pytest.fixture(scope="function")
               def init_def():
                   c= 3
                   print("函数前置")
                   yield c
                   print("函数后置")
                   
               @pytest.fixture(scope="class")
               def init_class_1():
                   a= 3
                   b=4
                   print("函数前置")
                   yield a,b      # 返回的是一个元组
                   print("函数后置")
           b). 测试函数调用时,需要
               -  测试类被装饰:@pytest.mark.usefixtures("init_def")
               -  测试函数内部调用变量时:
                   -- 函数定义参数中需要传入“前置后置函数名”,且内部调用情况如下
                      如: def test_add(self,init_def):
                               assert init_def>3
             
              另一种,返回多个值
              -  测试类被装饰:@pytest.mark.usefixtures("init_def_1")
              -  测试函数内部调用变量时:
                   -- 函数定义参数中需要传入“前置后置函数名”,且内部调用情况如下
                      如: def test_add(self,init_class_1):
                               # init_def_1是一个元组
                                assert init_class[0]>3
               )
        
       注意: 测试类其实可以同时使用init_class_1和init_def
           @pytest.mark.usefixtures("init_def")
           @pytest.mark.usefixtures("init_class_1")
           class TestLogin:
                def test_add(self,init_def):
                       assert init_def>3
                        
                def test_add(self,init_class_1):
                       # init_class_1是一个元组
                       assert init_class[0]>3
       
       注意:  scope=module, 代表py模块的前置后置,在模块中调用时,如果在第一个用例前用了,那么该模块会用,如果非第一个模块使用,那么该前置后置的作用域则在该用例及其之后(在执行第一个用例前不执行前置   

​ 存在疑问: 如果setUp()中用到了setUpClass()中的变量该怎么办?(待续) 注意误区: (setuUp不允许如下写法):
​ @pytest.mark.usefixtures(“init_def”)
​ @pytest.mark.usefixtures(“init_class_1”)
​ class TestLogin:

                def setup(self, init_class_1):
                    print(init_class_1)
                    
                def test_add(self,init_def):
                       assert init_def>3
      问题解决方案: 
           (前后置函数继承中的: 函数级别继承类级别的fixture前后置函数,就可解决上述问题)
2) 前置函数的继承
      import pytest
A. fixture函数继承:(继承不继承函数级别)
         '''
         a.  同级别fixture继承,那么执行顺序如下:
           被继承者前置---》继承者前置---》  (测试用例执行) ----》继承者后置----》被继承者后置(当继承多层的话,也是以此类推)
           (同级别的话, 包含,函数继承函数,类继承类级别的fixture前后置函数)
                  
         b.   函数级别继承了类级别的fixture前后置函数:
            被继承者前置---》(测试用例执行部分:
                          继承者前置---》执行用例1 》继承者后置----》
                          继承者前置---》执行用例2 》继承者后置----》
                          继承者前置---》执行用例1 》继承者后置----》
                          ......
            ---》被继承者后置 
            
        《注意》 在这里,如果setUp用到了setUpClass中的内容,
            且改变了,那么我们可创建一个变量用来接收setUpClass返回内容,修改相关内容,返回这个变量,接下来测试类引用后,就用的是改变之后的数据了(适用于driver对象)
            一般常用的就是上述两种继承,其他也可以去尝试  
            '''
         可看如下实例:
            a.  conftest中存在如下定义的函数:
                
                # 被继承者函数
                
                @pytest.fixture(scope="function")  
                def init_function_1():
                    a = 3
                    b = 4
                    print("==============函数前置==================")
                    yield a, b  
                    print("==============函数后置==============")

                @pytest.fixture(scope="class")  
                def init_class_11():
                    a = 3
                    b = 4
                    print("==============类前置==================")
                    yield a, b  
                    print("==============类后置==============")
               
                # 继承函数
                
                #  函数级别的fixture函数 继承函数级别的fixture函数
                @pytest.fixture(scope="function")
                def init2_function_1(init_function_1):
                    a = 10
                    print("py模块内的init2--函数前置")
                    yield a, init_function_1
                    print("py模块内的init2--函数后置")

                #  函数级别的fixture函数 继承“类”级别的fixture函数
                @pytest.fixture(scope="function")
                def init2_function_2(init_class_11):
                    a = 10
                    print("py模块内的init2--函数前置")
                    yield a, init_class_11
                    print("py模块内的init2--函数后置")

                #  类的fixture函数 继承“类”级别的fixture函数
                @pytest.fixture(scope="class")
                def init2_class_2(init_class_11):
                    a = 10
                    print("py模块内的init2--类前置")
                    yield a, init_class_11
                    print("py模块内的init2--类后置")
                
            b. 测试py模块中内容如下: 
            
                # @pytest.mark.usefixtures("init2_function_1")
                # @pytest.mark.usefixtures("init2_function_2")
                @pytest.mark.usefixtures("init2_class_2")
                class TestPyFixture1:
                
                    # def test_fixture_1(self, init2_function_1):
                    #     print("用例1")
                    #     print(init2_function_1)
                
                    def test_fixture_2(self):
                        print("用例2")
                
                    def test_fixture_3(self):
                        print("用例3")
B. Py模块中的fixture前后置函数
      '''
      如果fixture前置后置函数写在某个py模块中,那么:
          a. 它的作用域就是该py模块
          b. 如果autouse不是True,则需要在测试类或测试函数调用之后才可以使用(测试用例如果需要用到,那就fixture函数名当作参数传入用例函数中)
          c. 如果autouse是True,可以直接使用(测试用例如果需要用到,那就fixture函数名当作参数传入用例函数中)
            代码如下 : 
      '''        
    import pytest
    
    @pytest.fixture(scope="function")
    def init_function_1():
        a = 3
        b = 4
        print("==============函数前置==================")
        yield a, b
        print("==============函数后置==============")
        
    @pytest.fixture(scope="class")
    def init_class_11():
        a = 3
        b = 4
        print("==============类前置==================")
        yield a, b
        print("==============类后置==============")

    # Py模块代码如下:
    @pytest.fixture(scope="function")
    def init1():
        a = 10
        print("py模块内的init前置")
        yield a
        print("py模块内的init后置")
        
     
    @pytest.mark.usefixtures("init1")
    class TestPyFixture:
            
        def test_fixture_1(self, init1):
            print(init1)
            
        def test_fixture_2(self):
            pass

3) Pytest之fixture参数化(等同于ddt数据驱动)(待续)
     pytest层级覆盖,测试用例与其同级或者在其子目录 
5. Pycharm识别不到pytest----解决
    Pycharm右上角运行窗口左侧的”倒三角“符号点击--Edit Configurations->Defaults---->Pytest tests点击---> 点击“+”--->选择“Python tests”---->选择“pytest”/"py.test"--->选择项目路径--->完成 点击即可
6. Pytest之参数化
   在测试用例前面加上: @pytest.mark.parametrize("参数名",列表数据)
   参数名: 用来接收每一项数据,并用作测试用例参数
   列表数据: 一组测试数据
   @pytest.mark.parametrize("参数1,参数2",[(数据1,数据2),(数据1,数据2)....])
   
   实例:
   import pytest
    
    # 前后置函数
    @pytest.fixture(scope="function")
    def init_1():
        c = 8
        yield c
    
    # 测试函数
    @pytest.mark.usefixtures("init_1")
    class TestPytestDdt:
        """ pytest参数化运用---类似ddt"""
    
        cases_data = [(1, 0), (-1, 0), (0, 0), (1, -1)]
    
        @pytest.mark.parametrize('a,b', cases_data)
        def test_sum(self, a, b, init_1):
            sum = a + b + init_1
            assert sum == a + b + init_1
    
        @pytest.mark.parametrize('a,b', cases_data)
        def test_sum_1(self, a, b):
            sum = a + b
            assert sum == a + b
    
        @pytest.mark.parametrize("a", cases_data)
        def test_sum_2(self, a):
            sum = a[0] + a[1]
            assert sum == a[0] + a[1]  
7. pytest之指定用例运行
    # 1). 执行testddt和testfixture标签的用例
    # pytest.main(["-m", "testddt or testfixture",
    #              r"--html=reports\testReport.html"])

    # pytest.main(["-s", "-v", "-m", "testddt or testfixture",
    #              r"--html=reports\testReport.html"])

    # 2).  用例全量运行
    # pytest.main([r"--html=reports\testReport.html"])
    # 运行指定python包下的用例
    # pytest.main(["-v", r"Cases/caseq/"])

    # 3). 运行指定py模块下的用例
    # pytest.main(["-v", r"Cases/caseq/test_add.py"])

    # 4). 运行指定类的用例
    # pytest.main(["-v", r"Cases/caseq/test_add.py::TestClss"])

    # 5). 运行指定模块中指定函数名用例(检测不到测试类中同函数名的测试用例)
    # pytest.main(["-v", r"Cases/caseq/test_add.py::test_add_3"])

    # 6). 运行指定模块中指定内的指定用例
    pytest.main(["-v", r"Cases/caseq/test_add.py::TestClss::test_add_3"])
    
    (涉及路径的都是相对路径)
8. Pytest之html测试报告
    需要安装pytest-html: pip install pytest-html
    pytest可以生成多种样式的结果
    1) 生成JunitXML格式的测试报告,  命令 --junitxml=path
        (方便其他平台解析测试结果)
    2)  生成result log格式的测试报告,命令:--resultlog=report\log.txt
    3)  生成html格式的测试报告,命令: --html=report\test_one_func.html(相对路径)
    import pytest

    if __name__ == "__main__":  # 主函数入口
        # 执行testddt和testfixture标签的用例
        # pytest.main(["-m", "testddt or testfixture",
        #              r"--html=reports\testReport.html"])
    
        # pytest.main(["-s", "-v", "-m", "testddt or testfixture",
        #              r"--html=reports\testReport.html"])
9. 准备好allure环境
     (官方学习地址: http://allure.qatools.ru/) 
      1) 从Maven Center下载最新的安装包(手动安装):

http://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/
2) 将包解压到任何一个目录。进入到解压后的bin目录下面,windows下执行allure.bat
3) 系统变量新建: ALLURE_HOME = 解压路径
Path中追加: %ALLURE_HOME%\bin
(cmd窗口 allure --version来查看环境是否配置好)
4) 安装pytest的allure支撑插件
pip install allure-pytest

9. Pytest之allure测试:
  1) 执行pytest命令时,添加allure命令参数:--alluredir=Outputs/allure (相对于pytest命令所在目录的测试报告目录)
    if __name__ == '__main__':
        pytest.main(["-s","-v","--html=Outputs/reports/pytest.html",
             "--alluredir=Outputs/allure"])   # allure文件生成的目录
             
  2) 等待pytest执行完所有的测试用例,在Outputs/allure下会生成一些文件
      在cmd命令行当中,处于当前项目测试目录, 执行: “allure serve 测试结果文件目录” 命令就会生成漂亮的html报告

10.Pytest之Jekins集成
   Master/Slave模式:
   分担Jekins服务器压力,任务分配到其他执行机来执行
   Master: Jekins服务器
   Slave:   执行机(奴隶机),执行Master分配的任务,并返回任务进度和结果

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KhdKCGq-1600170492795)(C:\Users\Lujier\AppData\Roaming\Typora\typora-user-images\1575371500804.png)]

集成步骤如下(参考链接: http://www.lemfix.com/topics/348):

1)、在jenkins上安装allure插件。

Step1: 去jenkins插件网站上下载allure插件最新版本:

http://mirrors.jenkins-ci.org/plugins/allure-jenkins-plugin/

Step2: 打开jenkins,在系统管理 —> 插件管理 —>Advanced —> Upload Plugin

上传.phi格式的插件,点击[上传]操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值