zoukankan      html  css  js  c++  java
  • 畅谈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)

    技术分享图片

    技术分享图片

     
  • 相关阅读:
    【3-9】数据库基本应用
    Oracle所有分析函数<转>
    Oracle数据库row_number详解<转>
    MVC人员管理系统
    MVC Razor语法
    MVC基础
    邮箱验证
    jQuery入门基础(动画效果)
    js前台与后台数据交互
    ajax入门基础
  • 原文地址:https://www.cnblogs.com/wiki918/p/10078767.html
Copyright © 2011-2022 走看看