unittest基础概念

unittest是Python内置的单元测试框架,灵感来源于JUnit。核心概念包括:

  • Test Case(测试用例):最小的测试单元,继承自unittest.TestCase
  • Test Suite(测试套件):多个测试用例的集合
  • Test Runner(测试运行器):执行测试并输出结果
  • Fixture(测试夹具):测试前的准备和测试后的清理工作

二、编写第一个测试

创建一个简单的计算器类及其测试:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

# calculator.py

class Calculator:

    def add(self, a, b):

        return a + b

     

    def subtract(self, a, b):

        return a - b

     

    def multiply(self, a, b):

        return a * b

     

    def divide(self, a, b):

        if b == 0:

            raise ValueError("除数不能为零")

        return a / b

对应的测试代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

# test_calculator.py

import unittest

from calculator import Calculator

class TestCalculator(unittest.TestCase):

    def setUp(self):

        # 每个测试方法前执行

        self.calc = Calculator()

     

    def tearDown(self):

        # 每个测试方法后执行

        pass

     

    def test_add(self):

        self.assertEqual(self.calc.add(2, 3), 5)

        self.assertEqual(self.calc.add(-1, 1), 0)

     

    def test_subtract(self):

        self.assertEqual(self.calc.subtract(10, 5), 5)

        self.assertEqual(self.calc.subtract(-1, -1), 0)

     

    def test_multiply(self):

        self.assertEqual(self.calc.multiply(3, 4), 12)

        self.assertEqual(self.calc.multiply(-2, 3), -6)

     

    def test_divide(self):

        self.assertEqual(self.calc.divide(10, 2), 5)

        self.assertAlmostEqual(self.calc.divide(7, 2), 3.5)

     

    def test_divide_by_zero(self):

        with self.assertRaises(ValueError):

            self.calc.divide(10, 0)

if __name__ == '__main__':

    unittest.main()

三、常用断言方法

unittest.TestCase提供了丰富的断言方法:

方法 用途
assertEqual(a, b) 验证a == b
assertNotEqual(a, b) 验证a != b
assertTrue(x) 验证x为True
assertFalse(x) 验证x为False
assertIs(a, b) 验证a is b
assertIsNone(x) 验证x is None
assertIn(a, b) 验证a in b
assertIsInstance(a, b) 验证isinstance(a, b)
assertRaises(exc) 验证抛出异常
assertAlmostEqual(a, b) 验证浮点数近似相等

四、高级特性

1. 跳过测试与预期失败

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

import unittest

import sys

class TestAdvanced(unittest.TestCase):

    @unittest.skip("暂时跳过此测试")

    def test_skip(self):

        pass

     

    @unittest.skipIf(sys.platform == 'win32', 'Windows平台跳过')

    def test_skip_windows(self):

        pass

     

    @unittest.expectedFailure

    def test_expected_failure(self):

        self.assertEqual(1, 2# 已知会失败

2. 使用Mock对象

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

from unittest.mock import Mock, patch, MagicMock

# 创建Mock对象

mock = Mock()

mock.return_value = 42

print(mock())  # 输出: 42

# 使用patch装饰器

import requests

class TestAPI(unittest.TestCase):

    @patch('requests.get')

    def test_fetch_data(self, mock_get):

        mock_get.return_value.status_code = 200

        mock_get.return_value.json.return_value = {'data': 'test'}

         

        result = requests.get('https://api.example.com')

        self.assertEqual(result.status_code, 200)

        mock_get.assert_called_once()

五、测试组织与发现

对于大型项目,合理的测试组织至关重要:

1

2

3

4

5

6

7

8

project/

├── src/

│   ├── __init__.py

│   └── calculator.py

└── tests/

    ├── __init__.py

    ├── test_calculator.py

    └── test_integration.py

运行测试的多种方式:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

# 运行单个测试文件

python -m unittest test_calculator

# 运行具体测试类

python -m unittest test_calculator.TestCalculator

# 运行具体测试方法

python -m unittest test_calculator.TestCalculator.test_add

# 自动发现并运行所有测试

python -m unittest discover -s tests -v

# 生成HTML测试报告(需安装html-testRunner)

pip install html-testRunner

六、最佳实践总结

  1. 测试命名:使用test_前缀,描述清楚测试意图
  2. 独立性:每个测试应独立运行,不依赖其他测试
  3. 单一职责:一个测试只验证一个概念
  4. 使用setUp/tearDown:合理管理测试资源
  5. Mock外部依赖:单元测试应隔离外部系统
  6. 覆盖率目标:核心代码建议达到80%以上覆盖率

使用coverage工具检查测试覆盖率:

1

2

3

4

pip install coverage

coverage run -m unittest discover

coverage report

coverage html  # 生成HTML报告

更多推荐