美文网首页Python
Python 单元测试 - unittest

Python 单元测试 - unittest

作者: tafanfly | 来源:发表于2019-02-14 16:58 被阅读0次

    unittest是python内置的用于测试代码的模块,无需安装, 使用简单方便。

    unittest 简介

    unittest case的运行流程:

    • 写好一个完整的TestCase
    • 多个TestCase 由TestLoder被加载到TestSuite里面, TestSuite也可以嵌套TestSuite
    • 由TextTestRunner来执行TestSuite,测试的结果保存在TextTestResult中
    • TestFixture指的是环境准备和恢复

    unittest中最核心的部分是:TestFixture、TestCase、TestSuite、TestRunner


    Test Fixture

    用于测试环境的准备和恢复还原, 一般用到下面几个函数。

    • setUp():准备环境,执行每个测试用例的前置条件
    • tearDown():环境还原,执行每个测试用例的后置条件
    • setUpClass():必须使用@classmethod装饰器,所有case执行的前置条件,只运行一次
    • tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次

    Test Case

    • 参数verbosity可以控制错误报告的详细程度:默认为1。0,表示不输出每一个用例的执行结果;2表示详细的执行报告结果。
    • Verbosity=1情况下成功是 .,失败是 F,出错是 E,跳过是 S
    • 测试的执行跟方法的顺序没有关系, 默认按字母顺序
    • 每个测试方法均以 test 开头
    • Verbosity=2情况下会打印测试的注释

    被测代码,demo.py文件

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    def add(a, b):
        return a+b
    
    def minus(a, b):
        return a-b
    
    

    测试case, test_demo_class.py文件

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import unittest
    from demo import add, minus
    
    
    class TestDemo(unittest.TestCase):
        """Test mathfuc.py"""
    
        @classmethod
        def setUpClass(cls):
            print ("this setupclass() method only called once.\n")
    
        @classmethod
        def tearDownClass(cls):
            print ("this teardownclass() method only called once too.\n")
    
        def setUp(self):
            print ("do something before test : prepare environment.\n")
    
        def tearDown(self):
            print ("do something after test : clean up.\n")
    
        def test_add(self):
            """Test method add(a, b)"""
            self.assertEqual(3, add(1, 2))
            self.assertNotEqual(3, add(2, 2))
    
        def test_minus(self):
            """Test method minus(a, b)"""
            self.assertEqual(1, minus(3, 2))
            self.assertNotEqual(1, minus(3, 2))
    
        @unittest.skip("do't run as not ready")
        def test_minus_with_skip(self):
            """Test method minus(a, b)"""
            self.assertEqual(1, minus(3, 2))
            self.assertNotEqual(1, minus(3, 2))
    
    
    if __name__ == '__main__':
        # verbosity=*:默认是1;设为0,则不输出每一个用例的执行结果;2-输出详细的执行结果
        unittest.main(verbosity=1)
    

    Test Suite

    • 一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的

    • @unittest.skip()装饰器跳过某个case
      (1)skip():无条件跳过
      @unittest.skip("i don't want to run this case. ")
      (2)skipIf(condition,reason):如果condition为true,则 skip
      @unittest.skipIf(condition,reason)
      (3)skipUnless(condition,reason):如果condition为False,则skip
      @unittest.skipUnless(condition,reason)


    Test Loder

    • TestLoadder用来加载TestCase到TestSuite中。
    • loadTestsFrom*()方法从各个地方寻找testcase,创建实例,然后addTestSuite,再返回一个TestSuite实例
    • defaultTestLoader() 与 TestLoader()功能差不多,复用原有实例

    unittest.TestLoader().loadTestsFromTestCase(testCaseClass)
    unittest.TestLoader().loadTestsFromModule(module)
    unittest.TestLoader().loadTestsFromName(name,module=None)
    unittest.TestLoader().loadTestsFromNames(names,module=None)
    unittest.TestLoader().discover()

    实例如下, test_demo_module.py文件

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import sys
    import HTMLReport
    import unittest
    import test_demo_class
    from test_demo_class import TestDemo
    
    
    if __name__ == '__main__':
        paras = sys.argv[1:]
        args = paras[0]
        report = paras[1]
    
        suite = unittest.TestSuite()
        if args == 'test':
            tests = [TestDemo("test_minus"), TestDemo("test_add"), TestDemo("test_minus_with_skip")]
            suite.addTests(tests)
        elif args == 'tests':
            suite.addTest(TestDemo("test_minus"))
            suite.addTest(TestDemo("test_add"))
            suite.addTest(TestDemo("test_minus_with_skip"))
        elif args == 'class':
            suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestDemo))
        elif args == 'module':
            suite.addTests(unittest.TestLoader().loadTestsFromModule(test_demo_class))
        elif args == 'mix':
            suite.addTests(unittest.TestLoader().loadTestsFromName('test_demo_class.TestDemo.test_minus'))
        elif args == 'mixs':
            suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_demo_class.TestDemo.test_minus', 'test_demo_class.TestDemo', 'test_demo_class']))
        elif args == 'discover':
            suite.addTests(unittest.TestLoader().discover('.', 'test_*.py', top_level_dir=None))
    
        if report == 'terminal':
            runner = unittest.TextTestRunner(verbosity=1)
            runner.run(suite)
        elif report == 'txt':
            with open('ut_log.txt', 'a') as fp:
                runner = unittest.TextTestRunner(stream=fp, verbosity=1)
                runner.run(suite)
        elif report == 'html':
            runner = HTMLReport.TestRunner(report_file_name='test',
                                   output_path='report',
                                   title='测试报告',
                                   description='测试描述',
                                   sequential_execution=True
                                   )
            runner.run(suite)
    

    Testing Report

    • 终端报告: 如上terminal 分支
    • TXT报告: 如上txt 分支,当前目录会生成ut_log.txt文件
    • HTML 报告:如上html 分支,终端上打印运行信息同时会在当前目录生成report文件夹, 文件夹下有test.htmltest.log文件 更多见Python 单元测试 - HTML report
    HTML

    相关文章

      网友评论

        本文标题:Python 单元测试 - unittest

        本文链接:https://www.haomeiwen.com/subject/lioeeqtx.html