pyunit,Python Unit Test Framework
更多的关于TestCase、TestLoader、TestResult的内容,参考 https://docs.python.org/3/library/unittest.html)。
关于python unit架构,参考 https://blog.csdn.net/u012841352/article/details/71511890,Unit Test图示。
1. 基本框架 puthon unit test framework
- test fixture,测试准备
测试执行准备。包括相关的清理(cleanup)或 环境/数据初始化。 -- setup,teardown 和 __init__(),每个测试方法执行一次 - test case,测试用例
创建测试用例。为了某个特定目的,设计和执行测试数据、测试步骤,验证输出结果是否满足特定响应,断言(assert)。 -- pyunit的所有测试用例方法必须以 “test_“ ”开头 - test suite,测试套件
测试套件。为了某种测试目的,将一系列测试用例 或 测试套件组合在一起执行,类似文件夹。-- 调用 unittest.TestCase 创建基本的test case - test runner,测试执行
测试执行。执行测试用例 或 测试套件,输出测试结果,并对结果的正确性进行判断(assert),以文本 或 图表形式对测试结果进行整理、分析,生成测试报告。-- unittest TestLoader
2. Unit 文件构成
async_case.py
case.py #测试用例
loader.py #加载 test case 和 test suite
main.py
mock.py #使用mock(模拟)对像替代系统的某些部分,并对结果断言
result.py #测试结果
runner.py #执行测试并显示测试结果 -- 据此可扩展pyunit测试报告
signals.py
suite.py #测试套件
util.py
>> 由Unit Test Case构成的pyunit
test setup -> test method -> test teardown => call unit test
Import unitttest
# create test case
Class test_class_name(unittest.TestCase):
#preparation and clean test environment, must be repeated
Def setUp(self): #准备测试数据和测试环境,测试用例执行前执行;如果发生错误,其他测试方法均不会执行
pass
# create test method
Def test_caseName(self): #测试用例方法,必须以 test_ 开头
Self.assert…()
# run after test method run
Def tearDown(self): #run after setup is success #清理环境,恢复最初测试状态;测试用例执行完成 或 测试执行失败后执行(只要setup执行成功,teardown一定会执行)
pass
if __name__ = "__main__":
unitest.main() # runner, 测试用例方法执行
>> 由Unit Test Suit构成的pyunit
Import unitttest
# create test case
Class test_class_name(unittest.TestCase):
#preparation and clean test environment, must be repeated
Def setUp(self):
pass
# create test method
Def test_caseName(self):
Self.assert…()
# run after test method run
Def tearDown(self): #run after setup is success
pass
def suite(): #将测试用例组合到一测试套件,完成某种测试验证需求
suite = unittest.TestSuite()
suite.addTest(('test_caseName'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
>> 代码样例(以下基于此方法进行unit test编写)
import unittest
def pyjiou(n):
if(n%2 == 0):
print("ou shu")
return "ou shu"
else:
print("ji shu")
return "ji shu"
def py10(n):
if(n < 10):
print("less 10")
return "less 10"
else:
print("big 10")
return "big 10"
3. Python Unit module
'''
python unit test module, 2 class with 4 test methods with 7 assert(3 pass, 4 fail)
1. functest class with 3 test methods(6 assert: 3 pass, 3 fail) and setup, teardown
2. ft class with 1 test method(1 assert: 1 fail)
'''
class functest(unittest.TestCase):
def setUp(self):
print("test start -- : ")
def test_jiou(self):
print("method 1: test_jiou")
self.assertEqual(pyjiou(4),"ou shu") #pass
self.assertEqual(pyjiou(5),"ou shu") #fail
def test_py10(self):
print("method 2: test_py10")
self.assertEqual(py10(4),"less 10") #pass
self.assertEqual(py10(4),"big 10") #fail
def test_other(self):
print("method 3: test_other")
self.assertEqual('sup'.upper(),'SUP') #pass
self.assertTrue('sup'.isupper()) #fail
def tearDown(self):
print(" -- test end \n")
class ft(unittest.TestCase):
def test_data(self):
print("method 4: test_data")
self.assertEqual(pyjiou(1),"ou shu") #fail
4. Runner 测试执行
- python unit 文件中调用 test method 和 test suite
###call unit test case
if __name__ == "__main__":
unittest.main() # call unit test
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
###add test metho into test suite
def suite_all(): # merge test methods into test suite
suite = unittest.TestSuite()
suite.addTest(functest('test_jiou'))
suite.addTest(functest('test_py10'))
suite.addTest(functest('test_other'))
return suite
#call unit test suite
if __name__ == "__main__":
runner = unittest.TextTestRunner() # call unit test suite
runner.run(suite_all())
- 命令行调用 test method 和 test suite
python -m unittest #pyunit 基本命令
python -m unittest test_module1 test_module2 #执行多个指定文件中的unit method
python -m unittest test_module.TestClass #执行指定类中的unit metho
python -m unittest test_module.TestClass.test_method #执行指定类中的某个特定的test method
python -m unittest -v test_module #执行指定文件中的unit method,并输出详细测试结果
python -m unittest discover -s project_directory -p "*_test.py" #执行指定文件夹下(-s)的所有以test结尾的unit method
python -m unittest discover -t project_directory "*_test.py" #执行指定文件夹的顶层目录(-t)的所有以test结尾的unit method
# discover参数用来在指定目录下检出特定的unit method并执行测试
>> 测试结果
说明:
1)test method执行顺序:按class 和 method 名称的ascii排序
2)Ftest start:F - False,E - Error,. - Pass
more:也许你会发现这种标识(F, E, .),输出时有错位
====================== RESTART: D:\Project\python\punit.py =====================
method 4: test_data
ji shu
Ftest start -- : # each method with setup & tear down
method 1: test_jiou
ou shu
ji shu
-- test end
Ftest start -- :
method 3: test_other
-- test end
Ftest start -- :
method 2: test_py10
less 10
less 10
-- test end
F ####### fail method from this
======================================================================
FAIL: test_data (__main__.ft) # method 1
----------------------------------------------------------------------
Traceback (most recent call last):
File ".\punit.py", line 45, in test_data
self.assertEqual(pyjiou(1),"ou shu") #fail
AssertionError: 'ji shu' != 'ou shu'
- ji shu
+ ou shu
======================================================================
FAIL: test_jiou (__main__.functest) # method 2
----------------------------------------------------------------------
Traceback (most recent call last):
File ".\punit.py", line 29, in test_jiou
self.assertEqual(pyjiou(5),"ou shu") #fail
AssertionError: 'ji shu' != 'ou shu'
- ji shu
+ ou shu
======================================================================
FAIL: test_other (__main__.functest) # method 3
----------------------------------------------------------------------
Traceback (most recent call last):
File ".\punit.py", line 37, in test_other
self.assertTrue('sup'.isupper()) #fail
AssertionError: False is not true
======================================================================
FAIL: test_py10 (__main__.functest) # method 4
----------------------------------------------------------------------
Traceback (most recent call last):
File ".\punit.py", line 33, in test_py10
self.assertEqual(py10(4),"big 10") #fail
AssertionError: 'less 10' != 'big 10'
- less 10
+ big 10
----------------------------------------------------------------------
Ran 4 tests in 0.065s # 4 test method
FAILED (failures=4) # 4 fail
5. 测试断言(test assert)-- 未全部使用
Method | Checks that |
assertEqual(a, b) | a == b |
assertNotEqual(a, b) | a != b |
assertTrue(x) | bool(x) is True |
assertFalse(x) | bool(x) is False |
assertIs(a, b) | a is b |
assertIsNot(a, b) | a is not b |
assertIsNone(x) | x is None |
assertIsNotNone(x) | x is not None |
assertIn(a, b) | a in b |
assertNotIn(a, b) | a not in b |
assertIsInstance(a, b) | isinstance(a, b) |
assertNotIsInstance(a, b) | not isinstance(a, b) |
assertRaises(exc, fun, *args, **kwds) | fun(*args, **kwds) raises exc |
assertRaisesRegex(exc, r, fun, *args, **kwds) | fun(*args, **kwds) raises exc and the message matches regex r |
assertWarns(warn, fun, *args, **kwds) | fun(*args, **kwds) raises warn |
assertWarnsRegex(warn, r, fun, *args, **kwds) | fun(*args, **kwds) raises warn and the message matches regex r |
assertLogs(logger, level) | The with block logs on logger with minimum level |
assertAlmostEqual(a, b) | round(a-b, 7) == 0 |
assertNotAlmostEqual(a, b) | round(a-b, 7) != 0 |
assertGreater(a, b) | a > b |
assertGreaterEqual(a, b) | a >= b |
assertLess(a, b) | a < b |
assertLessEqual(a, b) | a <= b |
assertRegex(s, r) | r.search(s) |
assertNotRegex(s, r) | not r.search(s) |
assertCountEqual(a, b) | a and b have the same elements in the same number, regardless of their order. |
assertMultiLineEqual(a, b) | strings |
assertSequenceEqual(a, b) | sequences |
assertListEqual(a, b) | lists |
assertTupleEqual(a, b) | tuples |
assertSetEqual(a, b) | sets or frozensets |
assertDictEqual(a, b) | dicts |