时间:2021-05-23
unitest主要包含TestCase、TestSuite、TestLoader、TextTestRunner、TextTestResult这几个功能模块。
整个流程为:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中。
首先准备几个待测的方法,写在test_func.py中。
def add(a, b): return a + bdef multi(a, b): return a * bdef lower_str(string): return string.lower()def square(x): return x ** 2准备好几个待测的方法之后,为这些方法写一个测试用例,写入our_testcase.py中。
import unittestfrom test_func import *class TestFunc(unittest.TestCase): """Test test_func.py""" def test_add(self): """Test func add""" self.assertEqual(3, add(1, 2)) self.assertNotEqual(3, add(1, 3)) def test_multi(self): """Test func multi""" self.assertEqual(6, multi(2, 3)) self.assertNotEqual(8, multi(3, 3)) def test_lower_str(self): """Test func lower_str""" self.assertEqual("abc", lower_str("ABC")) self.assertNotEqual("Dce", lower_str("DCE")) def test_square(self): """Test func square""" self.assertEqual(17, square(4)) # 这里故意设计一个会出错的用例,测试4的平方等于17,实际上并不等于。 self.assertNotEqual(35, square(6))if __name__ == '__main__': unittest.main()这里写好之后,进入命令行终端,执行python our_testcase.py,执行结果如下。
...F======================================================================FAIL: test_square (__main__.TestFunc)Test func square----------------------------------------------------------------------Traceback (most recent call last): File "our_testcase.py", line 27, in test_square self.assertEqual(17, square(4))AssertionError: 17 != 16----------------------------------------------------------------------Ran 4 tests in 0.000sFAILED (failures=1)这里分析一下这个执行结果。首先能够看到一共运行了4个测试用例,失败了1个,并且给出了失败原因,AssertionError: 17 != 16,这是我们故意留下的错误漏洞,被测试用例测试出来了。
第一行...F中,一个点.代表测试成功,F代表失败,我们的测试结果中,前三个成功了,第四个失败了,总共是四个测试,其余的符号中E代表出错,S代表跳过。
特别说明的一点是,测试的执行顺序跟方法的顺序没有关系,四个测试是随机先后执行的。
每个测试方法编写的时候,都要以test开头,比如test_square,否则是不被unitest识别的。
在unitest.main()中加上verbosity参数可以控制输出的错误报告的详细程序,默认是1,如果设为0,则不输出每一用例的执行结果,即上面的第一行的执行结果内容。如果设为2,则输出详细的执行结果。
修改our_testcase.py中主函数。
if __name__ == '__main__': unittest.main(verbosity=2)执行结果如下。
test_add (__main__.TestFunc)Test func add ... oktest_lower_str (__main__.TestFunc)Test func lower_str ... oktest_multi (__main__.TestFunc)Test func multi ... oktest_square (__main__.TestFunc)Test func square ... FAIL======================================================================FAIL: test_square (__main__.TestFunc)Test func square----------------------------------------------------------------------Traceback (most recent call last): File "our_testcase.py", line 27, in test_square self.assertEqual(17, square(4))AssertionError: 17 != 16----------------------------------------------------------------------Ran 4 tests in 0.000sFAILED (failures=1)可以看到,每一个用例的详细执行情况以及用例名,用例描述均被输出了出来,在测试方法下加代码示例中的"""Doc String""",在用例执行时,会将该字符串作为此用例的描述,加合适的注释能够使输出的测试报告更加便于阅读。
按照上面的测试方法,我们无法控制用例执行的顺序,这样显然是不合理的,因为在一些测试过程中,我们肯定需要控制先测试某些用例,再测试某些用例,这些用例有先后的因果关系。在这里,我们就需要用到TestSuite。我们添加到TestSuite中的case是会按照添加的顺序执行的。
还有一个问题是,我们现在只有一个测试文件,我们直接执行该文件即可,但如果有多个测试文件,怎么进行组织,总不能一个个文件执行吧,答案也在TestSuite中。
新建一个文件,test_suite.py。
import unittestfrom our_testcase import TestFuncif __name__ == '__main__': suite = unittest.TestSuite() tests = [TestFunc("test_square"), TestFunc("test_lower_str"), TestFunc("test_multi")] suite.addTests(tests) runner = unittest.TextTestRunner(verbosity=2) runner.run(suite)执行结果如下。
test_square (our_testcase.TestFunc)Test func square ... FAILtest_lower_str (our_testcase.TestFunc)Test func lower_str ... oktest_multi (our_testcase.TestFunc)Test func multi ... ok======================================================================FAIL: test_square (our_testcase.TestFunc)Test func square----------------------------------------------------------------------Traceback (most recent call last): File "/Users/luyuze/projects/test/our_testcase.py", line 27, in test_square self.assertEqual(17, square(4))AssertionError: 17 != 16----------------------------------------------------------------------Ran 3 tests in 0.000sFAILED (failures=1)这样,用例执行的顺序就是按照我们添加进去的顺序来执行的了。
上面使用的是TestSuite的addTests()方法,并直接传入TestCase列表,也有一些其他的方法可以向TestSuite中添加用例。
# 直接用addTest方法添加单个TestCasesuite.addTest(TestMathFunc("test_multi"))# 使用loadTestFromName,传入模块名.TestCase名,下面俩方法效果相同suite.addTests(unittest.TestLoader().loadTestsFromName('our_testcase.TestFunc'))suite.addTests(unittest.TestLoader().loadTestsFromNames(['our_testcase.TestFunc']))# loadTestsFromTestCase(),传入TestCasesuite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFunc))用TestLoader的方法是无法对case进行排序的,同时,suite中也可以套suite。
用例组织好了,但是结果只能输出到控制台,这样没办法查看之前的执行记录,我们想将结果输出到文件。
修改test_suite.py。
import unittestfrom our_testcase import TestFuncif __name__ == '__main__': suite = unittest.TestSuite() tests = [TestFunc("test_square"), TestFunc("test_lower_str"), TestFunc("test_multi")] suite.addTests(tests) with open('UnitestTextReport.txt', 'a') as f: runner = unittest.TextTestRunner(stream=f, verbosity=2) runner.run(suite)在之前的测试中,可能会存在这样的问题:如果要在测试之前准备环境,测试完成之后做一些清理怎么办?这里需要用到的是setUp()和tearDown()。
修改our_testcase.py。
import unittestfrom test_func import *class TestFunc(unittest.TestCase): """Test test_func.py""" def setUp(self): print("do something before testcase") def test_add(self): """Test func add""" self.assertEqual(3, add(1, 2)) self.assertNotEqual(3, add(1, 3)) def test_multi(self): """Test func multi""" self.assertEqual(6, multi(2, 3)) self.assertNotEqual(8, multi(3, 3)) def test_lower_str(self): """Test func lower_str""" self.assertEqual("abc", lower_str("ABC")) self.assertNotEqual("Dce", lower_str("DCE")) def test_square(self): """Test func square""" self.assertEqual(17, square(4)) self.assertNotEqual(35, square(6)) def tearDownClass(self): print("do something after testcase")if __name__ == '__main__': unittest.main(verbosity=2)执行结果:
test_add (__main__.TestFunc)Test func add ... do something before testcasedo something after testcaseoktest_lower_str (__main__.TestFunc)Test func lower_str ... do something before testcasedo something after testcaseoktest_multi (__main__.TestFunc)Test func multi ... do something before testcasedo something after testcaseoktest_square (__main__.TestFunc)Test func square ... do something before testcasedo something after testcaseFAIL======================================================================FAIL: test_square (__main__.TestFunc)Test func square----------------------------------------------------------------------Traceback (most recent call last): File "our_testcase.py", line 30, in test_square self.assertEqual(17, square(4))AssertionError: 17 != 16----------------------------------------------------------------------Ran 4 tests in 0.001sFAILED (failures=1)可以发现setUp()和tearDown()在每个case前后都执行了一次。如果要在所有case执行之前和所有case执行之后准备和清理环境,我们可以使用setUpClass() 与 tearDownClass()。
class TestFunc(unittest.TestCase): """Test test_func.py""" @classmethod def setUpClass(cls): print "This setUpClass() method only called once." @classmethod def tearDownClass(cls): print "This tearDownClass() method only called once too."如果我们临时想要跳过某个case不执行,unitest也有相应的方法。
1、skip装饰器
# -*- coding: utf-8 -*-import unittestfrom test_func import *class TestFunc(unittest.TestCase): """Test test_func.py""" @unittest.skip('do not run this case') def test_add(self): """Test func add""" self.assertEqual(3, add(1, 2)) self.assertNotEqual(3, add(1, 3)) def test_multi(self): """Test func multi""" self.assertEqual(6, multi(2, 3)) self.assertNotEqual(8, multi(3, 3)) def test_lower_str(self): """Test func lower_str""" self.assertEqual("abc", lower_str("ABC")) self.assertNotEqual("Dce", lower_str("DCE")) def test_square(self): """Test func square""" self.assertEqual(17, square(4)) self.assertNotEqual(35, square(6))if __name__ == '__main__': unittest.main(verbosity=2)执行结果:
test_add (__main__.TestFunc)Test func add ... skipped 'do not run this case'test_lower_str (__main__.TestFunc)Test func lower_str ... oktest_multi (__main__.TestFunc)Test func multi ... oktest_square (__main__.TestFunc)Test func square ... FAIL======================================================================FAIL: test_square (__main__.TestFunc)Test func square----------------------------------------------------------------------Traceback (most recent call last): File "our_testcase.py", line 28, in test_square self.assertEqual(17, square(4))AssertionError: 17 != 16----------------------------------------------------------------------Ran 4 tests in 0.000sFAILED (failures=1, skipped=1)结果显示为,总共执行4个测试,1个失败,1个被跳过。
skip装饰器一共有三个 unittest.skip(reason)、unittest.skipIf(condition, reason)、unittest.skipUnless(condition, reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。
2、TestCase.skipTest()方法
class TestFunc(unittest.TestCase): """Test test_func.py""" def test_add(self): """Test func add""" self.skipTest("do not run this case") self.assertEqual(3, add(1, 2)) self.assertNotEqual(3, add(1, 3))效果与第一种是一样的。
以上就是全面介绍python中很常用的单元测试框架unitest的详细内容,更多关于python 单元测试框架unitest的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
之前,我曾转过一个单元测试框架系列的文章,里面介绍了unittest、nose/nose2与pytest这三个最受人欢迎的Python测试框架。本文想针对测试中
前言单元测试的重要性就不多说了,可恶的是Python中有太多的单元测试框架和工具,什么unittest,testtools,subunit,coverage,t
在进行使用的eclipse的进行开发的代码中,必然就会需要进行单元测试,在单元测试的情况提供较多的框架单元测试,例如使用junit单元测试,而在国外进行开发较好
Python中的单元测试我们先来回顾一下Python中的单元测试方法。下面是一个Python的单元测试简单的例子:假如我们开发一个除法的功能,有的同学可能觉得很
一、UnittestUnittest是Python标准库中自带的单元测试框架,Unittest有时候也被称为PyUnit,就像JUnit是Java语言的标准单元