python 单元测试 -- unittest
来源:互联网 发布:windows下启动nginx 编辑:程序博客网 时间:2024/06/08 00:56
python 单元测试 – unittest
@(python)
- python 单元测试 unittest
- 编写测试用例 test case
- 测试初始化和清理test fixture
- 测试套件 test suit
- 多个测试套件运行
- 使用 mock
- 参考
单元测试是对程序中的单个子程序、函数、过程进行的测试,面向白盒测试。
单元测试测试覆盖常用子程序的输入组合,边界条件和异常处理,尽可能保证单元测试代码简洁,避免单测本身代码有 bug 影响对测试对象的测试结果。
python 提供单元测试框架 unittest,
简单编写一个模块 calculator.py ,作为单元测试对象
#!/usr/bin/env python# coding=utf-8def my_print(str): pass #print(str)class Calculator(): __version__ = 4 def __init__(self, a, b): my_print("cal init") self.a = int(a) self.b = int(b) def __del__(self): my_print("cal del") def add(self): return self.a + self.b def sub(self): return self.a - self.b def mul(self): return self.a * self.b def div(self): return self.a / self.b
编写测试用例 (test case)
如上, 我们为该模块编写对应的单元测试,取名 testCalculator.py :
#!/usr/bin/env python# coding=utf-8import unittestfrom calculator import Calculatorclass CalculatorTest(unittest.TestCase): def test_add_0(self): cal = Calculator(8, 4) result = cal.add() self.assertEqual(result, 12) def test_add_1(self): cal = Calculator(8, 4) result = cal.add() self.assertNotEqual(result, 12) def will_not_callme(self): print("lalalla")if __name__ == "__main__": unittest.main()
简单地编写了两个对模块方法 add() 的测试用例。编写单元测试,我们需要对应测试的对象实现一个类,继承 unittest.TestCase
。
测试类 CalculatorTest
中的测试用例都是以 test_
, 其他方法在执行脚本的时候框架不会直接调用执行。
对应目标模块的各个方法编写测试用例,使用断言判断结果,注意使用的断言是 unittest.TestCase
内置的,这样才能保证不会由于某个用例断言失败而直接退出执行。
执行 运行结果如下,可以看到,没有通过的例子断言了错误的行号,可以快速定位问题。
$ python testCalculator.py -vtest_add_0 (__main__.CalculatorTest) ... oktest_add_1 (__main__.CalculatorTest) ... FAIL======================================================================FAIL: test_add_1 (__main__.CalculatorTest)----------------------------------------------------------------------Traceback (most recent call last): File "aa.py", line 16, in test_add_1 self.assertNotEqual(result, 12)AssertionError: 12 == 12----------------------------------------------------------------------Ran 2 tests in 0.002sFAILED (failures=1)
内置的断言
测试初始化和清理(test fixture)
看到上面的例子,每次写一个测试用例都要重新定义一个测试实例 cal, 显得很重复,但是直接在测试类初始化函数定义的话又怕用例之间相互干扰。还有就是,有些测试,需要测试前构建测试场景,测试结束后清理。
类似以上的问题,unittest 提供了几个方法实现。
- setUp() : 执行每个测试用例前都会调用,执行准备
- tearDown() : 执行完每个用例后都会调用,执行清理
对应上面两个方法,下面两个在测试类函数开始和结束调用
* setUpClass()
* tearDownClass()
测试套件 (test suit)
测试套件是多个测试用例的集合
结合上面内容,看个相对完整的测试套件 :
#!/usr/bin/env python# coding=utf-8import sysimport unittestfrom calculator import Calculatorclass CalculatorTest(unittest.TestCase): def setUp(self): self.cal = Calculator(8, 4) #assert 1 == 2, "test if setUp error" def tearDown(self): self.cal = None def test_add(self): ''' des : test add ''' result = self.cal.add() self.assertEqual(result, 12) # if use python builtin assert , it will stop run # assert result == 12, "add error" def test_sub(self): result = self.cal.sub() self.assertEqual(result, 4) def test_mul(self): result = self.cal.mul() self.assertEqual(result, 32) def test_div(self): result = self.cal.div() self.assertEqual(result, 2) @unittest.skip('just skip') def test_div_1(self): result = self.cal.div() self.assertEqual(result, 3) @unittest.skipIf(Calculator.__version__ < 5, 'not support this library') def test_div_2(self): result = self.cal.div() self.assertEqual(result, 2) @unittest.skipIf(Calculator.__version__ < 2, 'not support this library') def test_div_3(self): result = self.cal.div() self.assertEqual(result, 2) @unittest.skipUnless(sys.platform.startswith('win'), 'windows') def test_div_4(self): result = self.cal.div() self.assertEqual(result, 2) @unittest.skipUnless(sys.platform.startswith('linux'), 'linux') def test_div_5(self): result = self.cal.div() self.assertEqual(result, 2)def suite1(): ## 执行测试用例构建条件 suite = unittest.TestSuite() suite.addTest(CalculatorTest("test_add")) suite.addTest(CalculatorTest("test_sub")) return suitedef suite2(): # 指定前缀构建测试套件 suite = unittest.makeSuite(CalculatorTest, 'test') return suiteif __name__ == "__main__": ## 运行用例方法1 #my_print("Test suit : run some testcase") #runner = unittest.TextTestRunner() #runner.run(suite1()) ## 运行用例方法2 #my_print("Test suit : run all testcase") #runner.run(suite2()) ## 运行用例方法3 # python ./testCalculator.py -v # python ./testCalculator.py -v testCalculator.test_add my_print("Run all testcase dircetly") unittest.main()
关注的点:
* 测试用例指定条件,在不符合条件的情况下跳过不执行(见最后几个带修饰器的用例,对于跨平台什么实用)
* 所有测试用例执行顺序与其在类中的定义顺序没有关系,不能依靠这个先后关系;并且不同用例之间最好不要相互依赖。
如上,运行所有测试用例,或者指定某个测试用例运行。
$ python testCalculator.py -vtest_add (__main__.CalculatorTest) ... oktest_div (__main__.CalculatorTest) ... oktest_div_1 (__main__.CalculatorTest) ... skipped 'just skip'test_div_2 (__main__.CalculatorTest) ... skipped 'not support this library'test_div_3 (__main__.CalculatorTest) ... oktest_div_4 (__main__.CalculatorTest) ... skipped 'windows'test_div_5 (__main__.CalculatorTest) ... oktest_mul (__main__.CalculatorTest) ... oktest_sub (__main__.CalculatorTest) ... ok----------------------------------------------------------------------Ran 9 tests in 0.001sOK (skipped=3)
$ python testCalculator.py -v CalculatorTest.test_addtest_add (__main__.CalculatorTest) ... ok----------------------------------------------------------------------Ran 1 test in 0.001sOK
多个测试套件运行
$ python -m unittest discover ### 结合一下参数, python自动匹配运行所有符合条件的测试用例-v, --verboseVerbose output-s, --start-directory directoryDirectory to start discovery (. default)-p, --pattern patternPattern to match test files (test*.py default)-t, --top-level-directory directoryTop level directory of project (defaults to start directory)
或者直接新建一个文件,import 所有测试类
使用 mock
前面提到,单元测试测试最小单元,但是有时候测试,遇到测试模块需要依赖于其他模块,一个是不确定依赖的模块是否有问题;另一个是依赖模块容易构造获取,没有实现。比如网络消息分析包,需要接收网络字节之类的。
这种情况下,就需要对依赖的模块进行 mock,虚拟一个依赖模块供我们测试。
如上面的例子,假如原理的 add() 还没有实现
def add(self): pass
测试用例类似如下, 对其进行mock
from unittest import mock def test_add(self): result = self.cal.add() self.assertNotEqual(result, 12) self.cal.add = mock.Mock(return_value=12) result = self.cal.add() self.assertEqual(result, 12)
大概的意思,详细根据实际需求了解使用
参考 python mock
–
参考
- unittest doc
- 测试折腾的代码
- python--单元测试--unittest
- PYTHON单元测试模块unittest
- python单元测试unittest
- python-unittest模块【单元测试】
- python单元测试unittest
- python单元测试unittest
- python单元测试unittest
- python单元测试unittest
- Python单元测试框架unittest
- python单元测试unittest
- python单元测试unittest
- Python单元测试框架-unittest
- python的单元测试unittest
- python单元测试unittest
- python单元测试unittest
- python单元测试unittest
- Python unittest 单元测试
- Python单元测试模块---unittest
- js阻止冒泡事件-2
- 内存的工作原理和时序介绍
- 表单验证
- MFC基于对话框的工具栏定制效果
- 522. Longest Uncommon Subsequence II
- python 单元测试 -- unittest
- Andoird仿IOS滚轮选择控件
- shell 远程启动flume
- [Azure]ARM虚拟机整机磁盘快照[3]——清空虚拟机快照
- Java SE 6.0新特性体验(下篇)
- 欢迎使用CSDN-markdown编辑器
- 303. Range Sum Query
- Redis实战之Win7 64 + VS2013 + Redis 3.0 订阅和发布
- jdk 源码分析(17)java Semaphore 源码解析及与lock对比