单元测试
Max Zhang Lv4

单元测试

单元测试简介

在软件开发中,单元测试是一种测试方法,用来测试程序的最小单元,通常是一个函数或一个类。单元测试的目的是验证程序的正确性,确保程序的每一个部分都能正常工作。但是在实际开发中,很多程序员并不重视单元测试,认为它是一种浪费时间的行为,但是单元测试是重要的,可以提高程序的质量,减少复工。

单元测试框架

在 Python 中,有很多单元测试框架,这里我们主要介绍 unittest 单元测试框架。

unittest 单元测试框架

Person 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person:
def __init__(self, name: str, age: int):
self._name = name
self._age = age
self.__secret = "I am a secret!"

def get_name(self):
return self._name

def get_age(self):
return self._age

def get_secret(self):
return self.__secret

def set_secret(self, secret):
self.__secret = secret

unittest 编码:

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
# test_person.py

# 导入 unittest 模块
import unittest

# 导入要测试的类
from .person import Person

# 定义测试类
class TestPersonClass(unittest.TestCase):

# 测试 get_name 方法
def test_name(self):
person = Person("Tom", 18)
self.assertEqual(person.get_name(), "Tom")

# 测试 get_age 方法
def test_age(self):
person = Person("Tom", 18)
self.assertEqual(person.get_age(), 18)

# 测试 get_secret 方法
def test_secret(self):
person = Person("Tom", 18)
person.set_secret("test secret!")
self.assertEqual(person.get_secret(), "test secret!")

运行测试:

1
$ python -m unittest test_person.py

断言

断言指的是在程序中判断一个条件是否满足,如果满足就继续执行,如果不满足就抛出异常。

在单元测试中,我们通常使用断言来验证程序的正确性,unittest 框架提供了很多断言方法,常用方法包括:

  • assertEqual(a, b):判断 a 和 b 是否相等
  • assertNotEqual(a, b):判断 a 和 b 是否不相等
  • assertTrue(x):判断 x 是否为 True
  • assertFalse(x):判断 x 是否为 False
  • assertIs(a, b):判断 a 和 b 是否是同一个对象
  • assertIsNot(a, b):判断 a 和 b 是否不是同一个对象
  • assertIsNone(x):判断 x 是否为 None
  • assertIsNotNone(x):判断 x 是否不为 None

如上面的例子中,我们使用了 assertEqual 方法来判断两个值是否相等。

框架流程方法

在单元测试的过程中,unittest 框架提供了一些流程方法,可以在测试用例执行之前或之后执行一些操作,这些方法包括:

  • setUp 方法:在测试用例执行之前执行
  • tearDown 方法:在测试用例执行之后执行
  • setUpClass 方法:在测试类执行之前执行
  • tearDownClass 方法:在测试类执行之后执行

比如,我们可以在 setUp 方法中创建测试对象,然后在 tearDown 方法中销毁测试对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# test_person.py
class TestPersonClass(unittest.TestCase):
def setUp(self) -> None:
self.person = Person("Tom", 18)
return super().setUp()

def tearDown(self) -> None:
return super().tearDown()

def test_name(self):
self.assertEqual(self.person.get_name(), "Tom")

def test_age(self):
self.assertEqual(self.person.get_age(), 18)

def test_secret(self):
self.person.set_secret("test secret!")
self.assertEqual(self.person.get_secret(), "test secret!")

setUp 方法中创建了一个 Person 对象,这样就可以在测试用例中直接使用这个对象,而不需要在每个测试用例中都创建一个对象。

由于 setUp 方法是在测试用例执行之前执行的,所以是每个测试用例执行之前都会执行一次 setUp 方法,即使在测试用例中修改了对象的属性,也不会影响其他测试用例。

1
2
3
4
5
6
# test_person.py
class TestPersonClass(unittest.TestCase):
def setUpClass(self) -> None:
self.person = Person("Tom", 18)
return super().setUp()

如果将 setUp 方法改为 setUpClass 方法,那么这个方法就是在测试类执行之前执行的,也就是说,这个方法只会执行一次,而不是每个测试用例执行之前都会执行一次。这样如果在测试用例中修改了对象的属性,会影响其他测试用例。

单元测试通常测试的内容

通常情况下,单元测试应当覆盖一个类的公开方法,每一个方法都应当有一组测试用例,这些测试用例应当覆盖所有可能的情况,包括正常情况和异常情况。多使用等价类划分法和边界值分析法。

 评论
评论插件加载失败
正在加载评论插件