python 的单元测试框架是unittest。但我只想说,想放弃
python unitest的重要特性:
- 测试类继承自unittest.TestCase
- 测试函数须以test开头
- 每个测试函数之间是都是平行的,不可共享数据(平行宇宙)
关于第三点,本质上是由于每个case执行,都是new了不同的实例导致的。这是一个天坑。估计与python早期设计有关,是面向函数、面向模块、面向过程的,不是怎么面向类与对象。
基本测试用例
先来看最基本的使用。示例如下:
class TestAddition(unittest.TestCase):
# 测试类需要继承unittest.TestCase
def setUp(self):
# 每个测试方法前执行
print("Setting up the test")
def tearDown(self):
# 每个测试方法后执行
print("Tearing down the test")
def test_twoPlusTwo(self):
# 测试方法以test_打头,普通方法不进行测试
total = 2 + 2
self.assertEqual(4, total)
执行测试用例,只需要 unittest.main()
或使用TestSuite
,如:
if __name__ == '__main__':
# unittest.main()
#构造测试集
suite = unittest.TestSuite()
suite.addTest(TestAddition("test_division_case"))
#执行测试
runner = unittest.TextTestRunner()
runner.run(suite)
使用 IDE ,可以直接点击测试类或测试方法的箭头来执行:
天坑及注意事项
话说回来,unittest对比java的JUnitTest4,差了不止一星半点,它的设计思想也实在不敢恭维,想说比较反对人类。
- 每个测试方法的执行,都是通过新的实例来调用
- 也就是说不同测试方法之间,不能共享数据,变量不同步,状态不保持
- 多个测试函数,
__init__
函数会执行多次 - 多个测试函数,
setUp
函数会执行多次 - 多个测试函数,
tearDown
函数会执行多次 - 没有在所有测试之前执行的before函数
- 没有在所有测试之后执行的after函数
- 也就是说,setUp与tearDown虽然宣称用于初始化及清理,但他们在每个测试函数执行前后都会执行
- 也就是说,假如你在__init__、setUp函数中连接数据库,有多个测试方法,就打开并连接多少次数据库
- 你不能够,也不应该,将一个http请求结果,分成多个测试函数来校验。那会导致你每一次的测试函数都会产生一次http请求
很明显,unitest这个设计思路很清奇,超出了大家平时的理解。
假如要对某一个复杂数据进行校验,而且数据的获取还挺消耗性能,那么就不应该在测试类中去获取这个数据。
以下代码以及运行结果演示他这些特点
可以看到,__init__、setUp、tearDown
都执行了三次,且 test
方法之间的 self 实例都是不同的(哈希码不同)
class TestAddition(unittest.TestCase):
# 测试类需要继承unittest.TestCase
def setUp(self):
# 每个测试方法前执行
print("Setting up the test")
def tearDown(self):
# 每个测试方法后执行
print("Tearing down the test")
def test_twoPlusTwo(self):
# 测试方法以test_打头,普通方法不进行测试
total = 2 + 2
self.assertEqual(4, total)
def test_case1(self):
print('case1 self hash:{}'.format(self.__hash__()))
def test_case2(self):
print('case2 self hash:{}'.format(self.__hash__()))
if __name__ == '__main__':
# unittest.main()
mmd,我只想说。
—— end