Python单元测试模块unittest
- 1. 基本用法
- 2. 一个测试函数中可以包含多个断言
- 3. assertTrue断言和assertRaises断言
- 4. 例子
- 5. 为什么不用print而用unittest
1. 基本用法
假设有一个函数add
def add(x, y):
return x + y
如果我们想要测试这个函数的正确性,那么可以通过单元测试模块unittest
来进行
下面通过代码来讲解unittest
的用法
#导入模块
import unittest
# 首先创造一个测试类,这个类继承于unittest.TestCase
# 测试类的名字没有要求,但一般习惯于写成Test+<想要测试的类名>/<想要测试的函数名>的形式
class TestAdd(unittest.TestCase):
# 编写测试函数:注意,测试函数必须以test开头,unittest 框架自动识别并运行这些方法。
# 例如,如果函数名称改为add_test,那么unittest不会识别出这个方法
def test_add(self):
self.assertEqual(add(1, 2), 3) #检查add(1,2)是否等于3,这是unittest内置的一种断言
# 运行上面的测试类
# 下面这两行代码是固定的套路,记住就可以
if __name__ == '__main__':
unittest.main()
运行上面的代码,得到结果
第一行表明,unittest识别并且运行了一个测试函数(即test_add
)
第二行表明,所有的测试函数都通过了
2. 一个测试函数中可以包含多个断言
当然,在上面的测试函数test_add
中,如果我们想要测试多组数字,可以在test_add
中创建多个断言
import unittest
class TestAdd(unittest.TestCase):
def test_add(self):
# 真的断言
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(-1, -1), -2)
# 假的断言
self.assertEqual(add(3, 4), 5)
if __name__ == '__main__':
unittest.main()
在上面的代码中,我们创建了三个真的断言和一个假的断言。
运行代码,看看会发生什么
可以看到,unittest显示,在位于的文件中,第19行,
test_add
函数中,self.assertEqual(add(3, 4), 5)
没有通过。
并且指出了断言没有通过的原因:add(3,4)
等于7,7!=5,所以断言没有通过。
3. assertTrue断言和assertRaises断言
当然,除了assertEqual断言之外,unittest还提供了assertTrue断言,使用方法为
self.assertTrue(x) # 来判断x是否为真
以及判断异常的断言assertRaises,使用方法为
# 当执行代码的时候, 判断抛出的异常是否为我们想要的Error类型
with self.assertRaises(<Error 类型>):
<想要测试的代码>
4. 例子
下面,我们看一个例子,综合使用assertEqual,assertTrue以及assertRaises三种断言。
首先,我们编写一个银行账户类
class BankAccount:
def __init__(self, balance=0):
"""初始化
Args:
balance:银行账户的余额
"""
if balance < 0:
raise ValueError("Initial balance cannot be negative")
self.balance = balance
def deposit(self, amount):
"""存钱函数
Args:
amount: 想要存入的金额。如果amount<0,那么抛出ValueError异常
"""
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
def withdraw(self, amount):
"""取钱函数
Args:
amount:想要取出的金额。如果amount大于当前余额,那么抛出ValueError异常。
"""
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount
def is_overdrawn(self):
"""判断账户是否透支
"""
return self.balance < 0
下面,为银行账户类编写测试类
一般来说,对类进行测试的时候,我们会在测试类中编写一个setUp方法,用来实例化想要测试的类。
import unittest
class TestBankAccount(unittest.TestCase):
def setUp(self):
# 初始化一个初始余额为100的账户
self.account = BankAccount(100)
def test_initial_balance(self):
# 使用 assertEqual 验证初始余额
self.assertEqual(self.account.balance, 100)
def test_deposit(self):
# 存入50元,使用 assertEqual 验证余额变化
self.account.deposit(50)
self.assertEqual(self.account.balance, 150)
def test_withdraw(self):
# 提取30元,使用 assertEqual 验证余额变化
self.account.withdraw(30)
self.assertEqual(self.account.balance, 70)
def test_overdraw(self):
# 使用 assertRaises 验证提取超额时会抛出异常
with self.assertRaises(ValueError):
self.account.withdraw(200)
def test_deposit_negative_amount(self):
# 使用 assertRaises 验证存入负金额时抛出异常
with self.assertRaises(ValueError):
self.account.deposit(-50)
def test_is_overdrawn(self):
# 提取所有余额,验证账户是否透支
self.account.withdraw(100)
self.assertTrue(self.account.is_overdrawn() == False) # 账户余额为0,不应透支
def test_initial_balance_cannot_be_negative(self):
# 使用 assertRaises 验证初始余额不能为负
with self.assertRaises(ValueError):
BankAccount(-100)
if __name__ == '__main__':
unittest.main()
assertEqual
:
- 在
test_initial_balance
中,我们验证了初始余额是否为 100。 - 在
test_deposit
和test_withdraw
中,我们分别验证了存款和取款后余额是否与预期相符。
assertTrue
:
- 在
test_is_overdrawn
中,我们使用了assertTrue
来检查是否账户在余额为 0 时没有被透支。
assertRaises
:
- 在
test_overdraw
和test_deposit_negative_amount
中,我们验证当提取超过余额的金额或存入负数时,系统是否会抛出ValueError
。 - 在
test_initial_balance_cannot_be_negative
中,我们检查初始化账户时余额不能为负,如果为负,应该抛出异常。
运行上面的代码,结果为
表示测试全部通过。
5. 为什么不用print而用unittest
print 测试方式很难复用。一旦需要频繁修改测试内容,维护大量 print
语句将非常繁琐,测试逻辑和生产代码耦合在一起,代码会变得凌乱。
unittest 提供了结构化的测试方式,测试代码与生产代码分离。你可以很方便地更新测试内容,并确保每次修改代码时都有一套完整的测试用例来验证正确性。