• 畅谈python之单元测试框架-unittest


    一. unittest最核心的四个概念

    unittest中最核心的四个概念是:test case,test suite,test runner,test fixture

    技术分享图片

    TestCase:一个testcase的实例就是一个测试用例:测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)

    TestSuite:多个测试用例集合在一起

    TestLoader:是用来加载TestCase到TestSuite中的

    TextTestRunner:用来执行测试用例的。其中的run(test)会执行TestSuite/TestCase中的run(result)方法

    TextTestResult:保存TextTestRunner执行的测试结果

    fixture:测试用例环境的搭建和销毁(setUp/setUpClass,tearDown/tearDownClass)

    二. unittest初级使用

    1. 导入unittest模块、被测文件或者其中的类

    2. 创建一个测试类,并继承unittest.TestCase

    3. 重写setUp和tearDown方法(如果有初始化条件和结束条件)

    4. 定义测试函数,函数以test_开头

    5. 在函数体中使用断言来判断测试结果是否符合预期结果

    6. 调用unittest.main()方法来运行测试用例

    实例

    1. 在工程下创建一个My_UnitTest的包,在这个包下面,创建一个被测对象myClass.py和一个测试用例Test_Myclass.py

    技术分享图片

    2. 如果要测试数学中的加法和减法,测试对象myClass.py的内容为

    class Math:
    
        def add(self, a, b):
            return a + b
    
        def minus(self, a, b):
            return a - b

    3. 在测试用例中引入unittest,被测文件中的类,注意测试用例是以test_开头

    import unittest
    from revise.My_UnitTest.myClass import Math
    
    class Test_MyClass(unittest.TestCase):
    
        def setUp(self):
            self.m = Math()
    
        def tearDown(self):
            pass
    
        def test_add(self):
            result = self.m.add(100, 23)
            self.assertEqual(123, result)
    
        #减法
        def test_minus(self):
            result = self.m.minus(235, 111)
            self.assertEqual(124, result)

    4. 测试用例的执行顺序是以字母a-z和数字的从小到大的顺序来排列的,所以上述两个测试用例执行的顺序是add在前,minus再后,可以改改代码验证一下:

    import unittest
    from revise.My_UnitTest.myClass import Math
    
    class Test_MyClass(unittest.TestCase):
    
        def setUp(self):
            self.m = Math()
    
        def tearDown(self):
            pass
    
        def test_add(self):
            result = self.m.add(100, 23)
            print("我先执行")
            self.assertEqual(123, result)
    
        #减法
        def test_minus(self):
            result = self.m.minus(235, 111)
            print("我后执行")
            self.assertEqual(124, result)

    运行结果:

    Testing started at 12:36 ...
    D:Programpython34python.exe "D:ProgramPyCharm 2018.1.4helperspycharm\_jb_unittest_runner.py" --path D:/python_workshop/python6/revise/My_UnitTest/Test_Myclass.py
    Launching unittests with arguments python -m unittest D:/python_workshop/python6/revise/My_UnitTest/Test_Myclass.py in D:python_workshoppython6
    eviseMy_UnitTest
    我先执行
    我后执行
    
    
    Ran 2 tests in 0.001s
    
    OK

    如果希望minus先执行,add后执行,可以给前者函数名加一个1,后者加一个2

        def test_2_add(self):
            result = self.m.add(100, 23)
            print("我后执行")
            self.assertEqual(123, result)
    
        #减法
        def test_1_minus(self):
            result = self.m.minus(235, 111)
            print("我先执行")
            self.assertEqual(124, result)

    5. 如果在setUp里实例化被测文件中的类,那么每一条测试用例都要实例化一次被测类,用setUpClass()可以只实例化一次,同理,tearDownClass也只做一次收尾工作

        @classmethod
        def setUpClass(cls):
            cls.m = Math()
    
        @classmethod
        def tearDownClass(cls):
            pass

    6. 用unittest.main()的方法来运行测试用例Test_Myclass.py

    import unittest
    from revise.My_UnitTest.myClass import Math
    
    class Test_MyClass(unittest.TestCase):
    
        @classmethod
        def setUpClass(cls):
            cls.m = Math()
    
        @classmethod
        def tearDownClass(cls):
            pass
    
        def test_2_add(self):
            result = self.m.add(100, 23)
            print("我后执行")
            self.assertEqual(123, result)
    
        #减法
        def test_1_minus(self):
            result = self.m.minus(235, 111)
            print("我先执行")
            self.assertEqual(124, result)
    
    
    if "__name__" == "__main__":
        unittest.main()

    三. 断言Assert

    TestCase类提供了一系列的断言,即结果比对的函数

    Method

    Checks that

    New in

    assertEqual(a, b)

    a == b

     

    assertNotEqual(a, b)

    a != b

     

    assertTrue(x)

    bool(x) is True

     

    assertFalse(x)

    bool(x) is False

     

    assertIs(a, b)

    a is b

    3.1

    assertIsNot(a, b)

    a is not b

    3.1

    assertIsNone(x)

    x is None

    3.1

    assertIsNotNone(x)

    x is not None

    3.1

    assertIn(a, b)

    a in b

    3.1

    assertNotIn(a, b)

    a not in b

    3.1

    assertIsInstance(a, b)

    isinstance(a, b)

    3.2

    assertNotIsInstance(a, b)

    not isinstance(a, b)

    3.2

    四. unittest进阶使用

    方式一:类名("方法名")的集合

    testsuite:

      addTest()  添加一个测试用例

      addTests([..])  添加多个测试用例,addTests的参数是一个测试用例的集合

      注意:addTests中执行用例的顺序是按添加的先后顺序进行的,如果这样添加用例可能造成断言失败:

      suite.addTests([TestFileOperate("test_00_read_all"),
                    TestFileOperate("test_01_write_data"),
                    TestFileOperate("test_03_read_all"),
                    TestFileOperate("test_02_add_data")])

      正确的做法是:

      suite.addTests([TestFileOperate("test_00_read_all"),
                    TestFileOperate("test_01_write_data"),
                    TestFileOperate("test_02_add_data"),
                    TestFileOperate("test_03_read_all")])

    s = unittest.TestSuite()

    s.addTest(testStudent("test_do_homework"))

    runner = unittest.TextTestRunner()

    runner.run(s)

    实例1:addTest的使用

    在My_UnitTest包下创建一个main.py

    技术分享图片

    main.py中的代码如下:

    import unittest
    from revise.My_UnitTest.Test_Myclass import Test_MyClass
    
    #实例化测试套件对象
    s = unittest.TestSuite()
    #调用addTest来加载测试用例——addTest(类名("用例函数名称"))——添加一个测试用例
    s.addTest(Test_MyClass("test_add"))
    s.addTest(Test_MyClass("test_minus"))
    
    #使用TextTestRunner来运行测试用例
    #实例化
    runner = unittest.TextTestRunner()
    #用run方法就是用来运行测试用例的
    runner.run(s)

    运行结果,控制台输出如下:

    D:Programpython34python.exe D:/python_workshop/python6/revise/My_UnitTest/main.py
    ..
    ----------------------------------------------------------------------
    Ran 2 tests in 0.001s
    
    OK

    实例2:addTests的使用

    import unittest
    from revise.My_UnitTest.Test_Myclass import Test_MyClass
    
    #实例化测试套件对象
    s = unittest.TestSuite()
    #加载多个测试用例——参数为列表——列表当中为测试用例
    s.addTests([Test_MyClass("test_add"), Test_MyClass("test_minus")])
    #使用TextTestRunner来运行测试用例 #实例化 runner = unittest.TextTestRunner() #用run方法就是用来运行测试用例的 runner.run(s)

    运行结果:

    D:Programpython34python.exe D:/python_workshop/python6/revise/My_UnitTest/main.py
    ..
    ----------------------------------------------------------------------
    Ran 2 tests in 0.000s
    
    OK

    输出测试报告-text-到文件

    #创建一个文件,以写的方式打开

    fs = open("test_result.txt", "w")

    runner = unittest.TextTestRunner(fs)

    runner.run(s)

    实例3:输出测试报告到文件

    import unittest
    from revise.My_UnitTest.Test_Myclass import Test_MyClass
    
    #实例化测试套件对象
    s = unittest.TestSuite()
    #加载多个测试用例——参数为列表——列表当中为测试用例
    s.addTests([Test_MyClass("test_add"), Test_MyClass("test_minus")])
    
    #使用TextTestRunner来运行测试用例
    #打开一个文件
    fs = open("test_run_result.txt", "w")
    #实例化
    runner = unittest.TextTestRunner(fs)
    #用run方法就是用来运行测试用例的
    runner.run(s)

    运行结果,控制台没有输出,发现当前目录下多了一个文本文件test_run_result.txt

    技术分享图片

    控制台输出的信息写到文本文件中了

    技术分享图片

    方式二:unittest.TestLoader.discover方法匹配目录下的用例

    假如现在目录下存在两个测试用例,Test_Myclass.py和Test)_Myclass2.py,如果用addTests的方法添加用例到测试套件,未免有点麻烦,这时候需要使用TestLoader()这个类

    技术分享图片

    代码如下:

    import unittest, os
    
    #实例化测试套件对象
    s = unittest.TestSuite()
    #1.实例化TestLoader对象  2.使用discover去找到一个目录下的所有测试用例
    loader = unittest.TestLoader()
    #3.使用addTests将找到的测试用例放在测试套件下
    s.addTests(loader.discover(os.getcwd()))
    #运行 runner = unittest.TextTestRunner() runner.run(s)

    运行结果:

    ....
    ----------------------------------------------------------------------
    Ran 4 tests in 0.000s
    
    OK

    注意:源码中discover方法, start_dir是要寻找的目录路径,pattern是查找条件,即在指定的目录下查找以"test"开头的测试用例(事实上,这个查找是不区分大小写的,即Test开头的也能找到)

    技术分享图片

    方式三:unittest.TestLoader.loadTestsFromModule匹配模块中的测试用例

    ps:TetLoader类、TestSuite类需要先实例化再使用

    五. 美化测试报告—html

    python有提供第三方库支持输出的测试报告为html样式

    库名:HtmlTestRunner

    导入:from HtmlTestRunnerNew import HTMLTestRunner

    使用方式:

    s = unittest.TestSuite()

    s.addTests(测试用例)

    fp = open(dir_config.htmlreport_dir + "/API_autoTest_{0}.html".format(curTime), "wb")

    runner = HTMLTestRunnerNew.HTMLTestRunner(

          stream = fp,

          title = "QCD接口测试报告",

          description = "QCD接口测试报告",

          tester = "xiaozhai"

          )

    runner.run(s)

    代码修改如下:

    import unittest, os, time
    from HTMLTestRunnerNew import HTMLTestRunner
    
    #实例化测试套件对象
    s = unittest.TestSuite()
    #1.实例化TestLoader对象  2.使用discover去找到一个目录下的所有测试用例
    loader = unittest.TestLoader()
    #3.使用addTests将找到的测试用例放在测试套件下
    s.addTests(loader.discover(os.getcwd()))
    
    #获取当前时间
    curTime = time.strftime("%Y-%m-%d_%H-%M-%S")
    #在当前目录下创建一个html文件
    fp = open(os.getcwd() + "/autoTest_report_{0}.html".format(curTime), "wb")
    
    #运行测试用例,生成测试报告
    runner = HTMLTestRunner(
            stream=fp,
            title="单元测试报告",
            description="Math类的单元测试报告",
            tester="xiaozhai"
    )
    runner.run(s)

    运行效果:

    D:Programpython34python.exe D:/python_workshop/python6/revise/My_UnitTest/main.py
    ok test_add (Test_Myclass.Test_MyClass)
    ok test_minus (Test_Myclass.Test_MyClass)
    ok test_add (Test_Myclass2.Test_MyClass2)
    ok test_minus (Test_Myclass2.Test_MyClass2)
    
    Time Elapsed: 0:00:00.001000
    Sun Jul  8 18:17:18 2018 - Start Test:test_add (Test_Myclass.Test_MyClass)
    Sun Jul  8 18:17:18 2018 - Start Test:test_minus (Test_Myclass.Test_MyClass)
    Sun Jul  8 18:17:18 2018 - Start Test:test_add (Test_Myclass2.Test_MyClass2)
    Sun Jul  8 18:17:18 2018 - Start Test:test_minus (Test_Myclass2.Test_MyClass2)

    技术分享图片

    技术分享图片

     
  • 相关阅读:
    20200226 Java IO流——廖雪峰
    20200225 Java 多线程(2)-廖雪峰
    20200225 Java 多线程(1)-廖雪峰
    20200224 尚硅谷ElasticSearch【归档】
    20200224 一 概述
    20200222 尚硅谷Dubbo【归档】
    20200222 四、dubbo原理
    Improved robustness of reinforcement learning policies upon conversion to spiking neuronal network platforms applied to Atari Breakout game
    Reinforcement learning in populations of spiking neurons
    Solving the Distal Reward Problem through Linkage of STDP and Dopamine Signaling
  • 原文地址:https://www.cnblogs.com/wiki918/p/10078767.html
Copyright © 2020-2023  润新知