1. 简介

unittest单元测试框架是受到 JUnit(JAVA) 的启发,与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化,配置共享代码测试。支持将测试样例聚合到测试集中,并将测试与报告框架独立。

2. 构成

静态类图

unittest 框架 题_unittest

2.1 fixture

test fixture 表示为了开展一项或多项测试所需要进行的准备工作,以及所有相关的清理操作。举个例子,这可能包含创建临时或代理的数据库、目录,再或者启动一个服务器进程。

  • 应用级别为每个测试用例, 在用例 test1 test2 test3执行前后会分别执行setUp tearDown方法
import unittest

class TestDemo(unittest.TestCase):
    """Test demo.py"""

    def setUp(self):
        print("do something before test.Prepare environment.")
    
    def tearDown(self):
        print("do something after test.Teardown environment.")
        
    def test1(self):
        pass
    
    def test2(self):
        pass
    
    def test3(self):
        pass
  • 应用级别为测试类,在TestDemo测试类执行前后分别执行一次setUpClass tearDownClass

即使在这个测试类中有三个测试用例,但是fixture是 class 级别,所以只执行一次。

  • 重写类级别的fixture的时候需要使用@classmethod装饰器
import unittest

class TestDemo(unittest.TestCase):
    """Test demo.py"""
    
	@classmethod
    def setUpClass(cls):
        print("This setUpClass() method only called once.")

    @classmethod
    def tearDownClass(cls):
        print("This tearDownClass() method only called once too.")
        
    def test1(self):
        pass
    
    def test2(self):
        pass
    
    def test3(self):
        pass

2.2 test case

一个测试用例是一个独立的测试单元。它检查输入特定的数据时的响应。unittest提供一个基类:TestCase,用于新建测试用例。

  • 编写一个基于TestCase的测试类,类名一定要Test开头,里面的测试用例(类中方法)也是test开头,这样会被unittest识别并执行测试。
import unittest

class TestDemo(unittest.TestCase):
    """Test demo.py"""
    
    def test1(self):
        """make some assert"""
        self.assertEqual(1 > 2) 
    
    def test2(self):
        pass
    
    def test3(self):
        pass

2.3 test suite

test suite是一系列的测试用例,或测试套件,或两者皆有。它用于归档需要一起执行的测试。

  • 在编写完测试用例后,可以将需要执行测试的用例加入到test suite中,以便执行测试
  • suite中可以嵌套suite
import unittest

class TestDemo(unittest.TestCase):
    """Test demo.py"""
    
    def test1(self):
        """make some assert"""
        self.assertEqual(1 > 2) 
    
    def test2(self):
        pass
    
    def test3(self):
        pass
    

if __name__ == "__main__":
    # 创建一个 test suite
    suite = unittest.TestSuite()
	# 组成一个用例列表
    tests = [TestDemo("test1"), TestDemo("test2"), TestDemo("test3")]
    # 使用 .addTests 方法将列表中的用例添加至 suite 中
    suite.addTests(tests)
	# 执行用例
    runner = unittest.TextTestRunner(verbosity=2)
    runner.run(suite)

2.4 test runner

test runner是一个用于执行和输出测试结果的组件。这个运行器可能使用图形接口、文本接口,或返回一个特定的值表示运行测试的结果。
在上面的代码中已经有使用到 TextTestRunner

  • 首先创建一个 runner 对象
  • 执行 runner.run() 方法即可执行测试用例,参数为 test suite

2.5 assert

  • 常规断言方法
    | 方法 | 例子 |
    | — | — |
    | assertEqual(a,b) | a==b |
    | assertNotEqual(a,b) | a!=b |
    | assertTrue(x) | bool(x)isTrue |
    | assertFalse(x) | bool(x)isFalse |
    | assertIs(a,b) | aisb |
    | assertIsNot(a,b) | aisnotb |
    | assertIsNone(x) | xisNone |
    | assertIsNotNone(x) | xisnotNone |
    | assertIn(a,b) | ainb |
    | assertNotIn(a,b) | anotinb |
    | assertIsInstance(a,b) | isinstance(a,b) |
    | assertNotIsInstance(a,b) | notisinstance(a,b) |
  • 模糊断言方法
    | 方法 | 例子 |
    | — | — |
    | assertAlmostEqual(a,b) | round(a-b,7)==0 |
    | assertNotAlmostEqual(a,b) | round(a-b,7)!=0 |
    | assertGreater(a,b) | a>b |
    | assertGreaterEqual(a,b) | a>=b |
    | assertLess(a,b) | a<b |
    | assertLessEqual(a,b) | a<=b |
    | assertRegex(s,r) | r.search(s) |
    | assertNotRegex(s,r) | notr.search(s) |
    | assertCountEqual(a,b) | a and b have the same elements in the same number, regardless of their order. |

2.6 skip

当测试中出现某些原因我们不得不跳过一些测试用例的时候,需要用到skip()的一些方法。

  • @unittest.skip(reason)

跳过被此装饰器装饰的测试。reason为测试被跳过的原因。

  • @unittest.skipIf(condition,reason)

condition为真时,跳过被装饰的测试。

  • @unittest.skipUnless(condition,reason)

跳过被装饰的测试,除非condition为真。

  • @unittest.expectedFailure

将测试标记为预期的失败或错误。如果测试失败或错误,它将被视为成功。如果测试通过,它将被视为失败。

  • exceptionunittest.SkipTest(reason)

引发此异常以跳过一个测试。
通常来说,你可以使用TestCase.skipTest()或其中一个跳过测试的装饰器实现跳过测试的功能,而不是直接引发此异常。

被跳过的测试的**setUp()****tearDown()**不会被运行。被跳过的类的**setUpClass()****tearDownClass()**不会被运行。被跳过的模块的**setUpModule()****tearDownModule()**不会被运行。