python基础之类与对象的应用-单元测试unittest模块

单元测试的本质

测试函数,从代码级别上进行测试

单元测试的框架

python+unittest

unittest模块

  • python自带不需安装

  • 结构

    • 写用例 Testcase --- 方法
    • 执行用例
      • 1.TestSuite 存储用例 --- 类
      • 2.TestLoader 找用例,加载用例,存到1中的TestSuite --- 类
    • 对比实际结果 断言 Assert
    • 出具测试报告 TextTestRunner
  • 测试自己的类

    python基础之初识类与对象 超继承示例中的MathMethod类

    #测试MathMethod类
    
    from py_0909.super import MathMethod #导入待测的类
    import unittest
    
    class TestMathMethod(unittest.TestCase):#继承与unittest的Testcase方法
    
        #编写测试用例
        def test_add_two_positive(self): #测试两个正数相加
            res=MathMethod(1,1).add() #实例化调用待测的方法
            print("1+1的结果是:",res)
    
        def test_add_two_zero(self): #测试两个0相加
            res = MathMethod(0, 0).add()
            print("0+0的结果是:", res)
    
        def test_add_two_negative(self): #测试两个负数相加
            res = MathMethod(-1, -1).add()
            print("-1+(-1)的结果是:", res)
    
    if __name__ == '__main__':
        unittest.main() #unitest.main()函数用来测试类中以test开头的测试用例
    

    运行测试用例的结果:


    python基础之类与对象的应用-单元测试unittest模块_第1张图片
    image
  • 说明

    • 一个用例是一个函数,不能传参,只有self关键字

    • 所有的用例都是test开头,test_,例如test_add_two_positive

    • Testcase默认的执行顺序是按函数名的ASCII码

配置测试用例的执行顺序

  • 如果想测试用例不按默认的执行顺序,可以通过TestSuite类、TestLoader类搭配使用配置测试用例执行顺序

  • TestSuite类说明(command键+鼠标左键进入)

    • TestSuite测试套件是由测试用例组成的复合测试。

    • 要使用,请创建testsuite的实例,然后添加测试用例实例。使用suite.add('方法名')添加测试用例

    • 添加完测试用例后,将TestSuite传递给TextTestRunner

    • 它将按添加顺序运行各个测试用例

  • 执行少量用例时,配置测试用例顺序

    #新建一个py文件
    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    
    #创建TestSuite实例,存储测试用例
    suite=unittest.TestSuite() 
    
    #构造测试套件
    suite.addTest(TestMathMethod('test_add_two_positive')) #添加测试用例,必须传入参数--函数名
    suite.addTest(TestMathMethod('test_add_two_zero'))
    suite.addTest(TestMathMethod('test_add_two_negative'))
    
    #执行用例
    runner=unittest.TextTestRunner() 
    runner.run(suite)
    

    运行结果: 按我们添加测试用例的顺序执行


    python基础之类与对象的应用-单元测试unittest模块_第2张图片
    image
  • 执行大量用例的方法,使用TestLoader

    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    #创建一个加载器
    suite=unittest.TestSuite() #创建TestSuite实例,存储测试用例
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestMathMethod))
    # 从测试类里去找 import也需要导到模块处 搭配loadTestsFromModule使用
    # from py_inter0913 import unittest_01
    # suite.addTest(loader.loadTestsFromModule(unittest_01))
    
    #执行用例
    runner=unittest.TextTestRunner()
    runner.run(suite)
    
  • setUp()和tearDown()

    在测试类中添加setUp()、tearDown()方法,会在单条测试用执行开始前和结束后执行。

    • setUp()、tearDown()是TestCase里的方法,写在测试类中,就是方法的重写。
    class TestMathMethod(unittest.TestCase):
    def setUp(self):
        print("准备开始执行测试用例了")
        
    def tearDown(self):
        print("结束了")
        
    #编写测试用例
    def test_add_two_positive(self): #测试两个正数相加
        res=MathMethod(1,1).add()
        print("1+1的结果是:",res)
    
    • 执行顺序是:
      setUp->testA->tearDown->setUp->testB>tearDown

断言

断言就是预期结果。如果不加断言,没有结果对比,需要手动去检查运行的结果是否符合预期。

  • assertEqual()

    def assertEqual(self, first, second, msg=None):
        """Fail if the two objects are unequal as determined by the '=='
           operator.
        """
    
    • first 预期结果
    • second 实际结果
    • msg 出错时,输出的错误信息,可不填
  • 断言使用

    在测试用例中写入断言

    from py_0909.super import MathMethod #导入待测的类
    import unittest
    
    #测试MathMethod类
    class TestMathMethod(unittest.TestCase):
        #编写测试用例
        def test_add_two_positive(self): #测试两个正数相加
            res=MathMethod(1,1).add()
            print("1+1的结果是:",res)
            self.assertEqual(2,res,"两个正数相加出错了") #断言
    
        def test_add_two_zero(self): #测试两个0相加
            res = MathMethod(0, 0).add()
            print("0+0的结果是:", res)
            self.assertEqual(0, res, "两个0相加出错了") #断言
    
        def test_add_two_negative(self): #测试两个负数相加
            res = MathMethod(-1, -1).add()
            print("-1+(-1)的结果是:", res)
            self.assertEqual(-2, res, "两个负数相加出错了") #断言
    
    if __name__ == '__main__':
        unittest.main()
    
  • 其他断言语法


    python基础之类与对象的应用-单元测试unittest模块_第3张图片
    image
  • 断言的异常处理

    from py_0909.super import MathMethod #导入待测的类
    import unittest
    
    #测试MathMethod类
    class TestMathMethod(unittest.TestCase):
        #编写测试用例
        def test_add_two_positive(self): #测试两个正数相加
            res=MathMethod(1,1).add()
            print("1+1的结果是:",res)
            try: #断言的异常处理
                self.assertEqual(0,res,"两个正数相加出错了") #断言
            except AssertionError as e:
                print("断言出错,错误是:{0}".format(e)) #对异常的处理:输出错误语句、存储到excel等
                raise e #异常处理完要抛出去,否则输出结果中不会报错
    
        def test_add_two_zero(self): #测试两个0相加
            res = MathMethod(0, 0).add()
            print("0+0的结果是:", res)
            try:
                self.assertEqual(1, res, "两个0相加出错了") #断言
            except AssertionError as e:
                print("断言出错,错误是:{0}".format(e))
                raise e
    
        def test_add_two_negative(self): #测试两个负数相加
            res = MathMethod(-1, -1).add()
            print("-1+(-1)的结果是:", res)
            try:
                self.assertEqual(-1, res, "两个负数相加出错了") #断言
            except AssertionError as e:
                print("断言出错,错误是:{0}".format(e))
                raise e
    
    if __name__ == '__main__':
        unittest.main()
    
    • 从错误的输出可以知道,异常的基类是AssertionError。
    • 捕获异常,要对异常进行处理,处理之后,要将异常抛出,否则在结果报告中,不会报错。raise e

测试报告

  • TextTestRunner


    python基础之类与对象的应用-单元测试unittest模块_第4张图片
    image

    TextTestRunner是一个以文本形式展示测试结果的测试运行程序类

    • stream 输出报告的路径,默认输出控制台
    • verbosity 控制输出报告的详细程度,从0-2,越来越详细
    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    suite=unittest.TestSuite() #创建TestSuite实例,存储测试用例
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestMathMethod))
    
    #执行用例
    with open("result.txt","w+") as file:
        runner=unittest.TextTestRunner(stream=file,verbosity=2)
        runner.run(suite)
    
  • HTMLTestRunner

    使用unittest自带的报告不够美观。HTMLTestRunner是Python标准库的unittest模块的扩展。它生成易于使用的HTML测试报告。

    • HTMLTestRunner是Python标准库的unittest模块的扩展,无法通过pip安装
    • 下载HTMLTestRunner.py放在lib目录下,下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html
    • 导入模块 import HTMLTestRunner
    import HTMLTestRunner
    import unittest
    from py_inter0913.unittest_01 import TestMathMethod #导入写了测试用例的类
    suite=unittest.TestSuite() #创建TestSuite实例,存储测试用例
    loader=unittest.TestLoader()
    suite.addTest(loader.loadTestsFromTestCase(TestMathMethod))
    
    with open("result.html","wb") as file:
        runner=HTMLTestRunner.HTMLTestRunner(stream=file, title="MathMethod测试", verbosity=2,)
        runner.run(suite)
    
    

    运行之后会发现报错:No module named 'StringIO',原因是自己使用python3,而下载的HTMLTestRunner适用于Python2.X,需要自己对模块进行修改。

    参考文档:https://www.bbsmax.com/A/QW5YL9jeJm/

    • html格式的报告:
    python基础之类与对象的应用-单元测试unittest模块_第5张图片
    image

    实战中问题

    • SSLError:http://2.python-requests.org/zh_CN/latest/user/advanced.html#ssl

      方法1.在参数中加入verify=False可以不进行安全验证,requests.get('https://github.com', verify=True)

      方法2.为 verify 传入 CA_BUNDLE 文件的路径,或者包含可信任 CA 证书文件的文件夹路径。requests.get('https://github.com', verify='/path/to/certfile')

- 作业思路
    - 测试用例.py
        - 实例化调用被测类的方法进行测试用例编写
        - 断言
        - 异常处理
    - 测试套件.py
        - 存储要运行的测试用例
        - 执行测试套件中的测试用例
        - 根据测试套件.py中生成测试报告
        
- cookie处理

    - 相当于面试题:后面的用例需要用到前面返回的某些值如何解决?

    - 方法1:setUp()方法
    
        大部分请求都要带着cookie,可以写一个登录的用例到`def setUp()`中,每一条用例都采用登录的cookie
        ```
        def setUp():
            response=request.get(url,data)
            cookie=response.request.cookie
            
        def add(self,url,data,cookie):
            ...
            
        ```
    - 方法2:全局变量 
        ```
        COOKIE=None #全局变量

        class TestHttp(unittest.Testcase):
            def add(self):
                golbal COOKIE #声明全局变量
                response=request.get(url,data)
                if response.cookies: #如果response.cookies有值
                    COOKIE=response.cookies #给全局变量赋新值
        ```
        缺点是关联性太强,比如登录失败,其他都跪了
    
    - 方法3:反射机制 setattr\hasattr\getattr\delattr
    
        `setattr(类名,"属性名","属性值")`
        
        ```
        # 示例
        class GetData:
            Cookie="小郭"

        if __name__ == '__main__':
            print(GetData.Cookie)
            setattr(GetData,"Cookie","小黄")#set类中的属性值进行修改,attr--attribute
            print(GetData.Cookie)
            print(hasattr(GetData,"Cookie"))#判断是否有这个属性
            print(getattr(GetData,"Cookie"))#获取这个属性的值
            delattr(GetData,"Cookie") #删除这个属性
            print(hasattr(GetData,"Cookie"))
        ```
        
        实战应用:
        ```
        #get_data.py文件
        class GetData:
            Cookie=None
        ```
        
        ```
        #测试用例.py
        from xxx import get_data
        class TestHttp(unittest.Testcase):
            def add(self):
                golbal COOKIE #声明全局变量
                response=request.get(url,data,getattr(GetData,"Cookie"))
                
        ```

unittest总结

  • unittest原理


    python基础之类与对象的应用-单元测试unittest模块_第6张图片
    image
  • unittest核心步骤

    • testcase 一个testcase的示例就是一条测试用例
- testsuite 多个测试用例组成一个suite

    - 方法一:suite.addTest("测试用例的函数名")
    - 方法二:TestLoader
        ```
        loader=unittest.TestLoader()
        #该测试类中以test_开头的用例都加载进来
        suite.addTest(loader.loadTestFromTestCase(测试用例的类名))
        #该模块中以test_开头的用例都加载进来,一个模块可能有多个测试类,需要import该模块
        suite.addTest(loader.loadTestFromModule(模块名))
        ```

- testrunner 执行用例
```
runner=unittest.TextTestRunner()
runner.run(suite)
```

- test fixture

你可能感兴趣的:(python基础之类与对象的应用-单元测试unittest模块)