[Dynamic Language] Python Library: unittest
Python Library: unittest
对于熟悉 NUnit 的人来说,Python unittest 可以很快上手。
- TestCase, FunctionTestCase: 创建包含测试方法的测试用例。
- TestSuite: 组合多个测试用例,用于批量测试。
- TestLoader: 可通过多种手段自动查找测试用例,返回 TestSuite。
- TestRunner, TextTestRunner: 执行测试用例,并输出测试结果。
- TestResult: 保存测试结果信息。
测试相等性
TestCase
包含一对方法assertEqual
和assertNotEqual
用于测试相等性。
如:
self.assertEqual(self.instance.func1(), 3)
测试异常
TestCase
有一个assertRaises
方法。此方法的前两个参数是应该出现在“except”语句中的异常和可调用对象。剩余的参数是应该传递给可调用对象的参数。
如:
self.assertRaises(ValueError, self.widget.resize, -1, -1)
简单实例
abeen@localhost:~/learn_test/unittest$ cat test.py
#! /usr/bin/env python
# _*_ coding: utf-8 _*_
import sys
import unittest
from unittest import TestCase, FunctionTestCase, TestSuite, TextTestRunner, defaultTestLoader
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def func1(self):
return self.x + self.y
def func2(self):
return self.x - self.y
class TestMyClass(TestCase):
def setUp(self):
print "setUp", hex(id(self))
self.instance = MyClass(1,2)
def tearDown(self):
print "tearDown"
def test_func1(self):
self.assertEqual(self.instance.func1(), 3)
def test_func2(self):
self.assertEqual(self.instance.func2(), -1)
if __name__ == "__main__":
unittest.main()
abeen@localhost:~/learn_test/unittest$ python test.py
EsetUp 0x7f752e9731d0
tearDown
.setUp 0x7f752e973250
tearDown
.
----------------------------------------------------------------------
Ran 3 tests in 0.000s
FAILED (errors=0)
(1) 默认测试对象(TestMyClass)中以 "test" 开头的都被认为是测试方法,相当于 NUnit 当中添加 "[Test]" 特性的方法。
(2) setUp / tearDown 在每个测试函数执行前后被调用。
(3) 测试对象不会重复使用,每次都创建了新实例。
用suite来组织一个有前后顺序依赖的完整测试逻辑。
abeen@localhost:~/learn_test/unittest$ cat test.py
...
if __name__ == "__main__":
"""unittest.main()"""
suite = TestSuite()
suite.addTest(TestMyClass("test_func1"))
suite.addTest(TestMyClass("test_func2"))
TextTestRunner().run(suite)
运行测试
abeen@localhost:~/learn_test/unittest$ python test.py
setUp 0x7f15a0ac1cd0
tearDown
.setUp 0x7f15a0ac1d10
tearDown
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
还有更简便的方法创建Suite, TestLoader提供了多种方法“自动、批量”完成这类工作....
if __name__ == "__main__":
"""unittest.main()"""
"""
suite = TestSuite()
suite.addTest(TestMyClass("test_func1"))
suite.addTest(TestMyClass("test_func2"))
TextTestRunner().run(suite)
"""
suite = defaultTestLoader.loadTestsFromTestCase(TestMyClass)
TextTestRunner().run(suite)
运行测试
abeen@localhost:~/learn_test/unittest$ python test.py
setUp 0x7f3d073cecd0
tearDown
.setUp 0x7f3d073ced50
tearDown
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
我们自己该造一个更好用的方法来试试看
abeen@localhost:~/learn_test/unittest$ cat test.py
#! /usr/bin/env python
# _*_ coding: utf-8 _*_
import sys
import unittest
from unittest import TestCase, FunctionTestCase, TestSuite, TextTestRunner, defaultTestLoader
class MyClass(object):
def __init__(self, x, y):
self.x = x
self.y = y
def func1(self):
return self.x + self.y
def func2(self):
return self.x - self.y
def MyFunc(x, y):
return x + y
"""自己定义测试类"""
class MyFunctionTestCase(FunctionTestCase):
def _func(self, name):
attr_name = "_{0}__{1}Func".format(self.__class__.__base__.__name__, name)
return getattr(self, attr_name)
def setUp(self):
func = self._func("setUp")
if func is not None: func(self)
def tearDown(self):
func = self._func("tearDown")
if func is not None: func(self)
def runTest(self):
func = self._func("test")
func(self)
if __name__ == "__main__":
def setUp(self):
self.o = MyClass(1, 2)
test1 = MyFunctionTestCase(lambda self: self.assertEqual(MyFunc(1,2), 3), None)
test2 = MyFunctionTestCase(lambda self: self.assertEqual(self.o.func1(), 3), setUp)
test3 = MyFunctionTestCase(lambda self: self.assertEqual(self.o.func2(), -1), setUp)
suite = TestSuite()
suite.addTests((test1, test2, test3))
TextTestRunner().run(suite)
测试结果
abeen@localhost:~/learn_test/unittest$ python test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
---------------------------------------------------------------
参考文档: