在日常的自动化测试过程中,Python里有一个自带的单元测试框架是unittest模块,简单易用,这里简单介绍下其主要的用法。
Unittest测试框架主要包含四个部分
- TestCase 也就是测试用例
- TestSuite 多个测试用例集合在一起,就是TestSuite
- TestLoader是用来加载TestCase到TestSuite中的
- TestRunner是来执行测试用例的,测试的结果会保存到TestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息
这里盗一波图来图文并茂的介绍一波框架运作流程:

来一发实例。压压惊~
第一步:编写测试用例:
- # -*- coding: utf-8 -*-
- #先设置编码,utf-8可支持中英文,如上,一般放在第一行
- #注释:包括记录创建时间,创建人,项目名称。
- '''
- Created on 2018-10-12xxxx
- __author__ = 'xxxx'
- Project:使用unittest框架编写测试用例
- '''
- import unittest
- #定义测试类,父类为unittest.TestCase。
- #可继承unittest.TestCase的方法,如setUp和tearDown方法,不过此方法可以在子类重写,覆盖父类方法。
- #可继承unittest.TestCase的各种断言方法。
- from mathFunc import *
- class TestMathFunc(unittest.TestCase):
- """Test mathfuc.py"""
- #定义setUp()方法用于测试用例执行前的初始化工作。
- #注意,所有类中方法的入参为self,定义方法的变量也要“self.变量”
- #针对每个测试用例的初始化及结尾工作
- @classmethod
- def setUpClass(cls):
- print "This setUpClass() method only called once."
- #定义tearDown()方法用于测试用例执行之后的善后工作
- @classmethod
- def tearDownClass(cls):
- print "This tearDownClass() method only called once too."
- # def setUp(self):
- # def tearDown(self):
- #定义测试用例,以“test_”开头命名的方法
- #注意,方法的入参为self
- #可使用unittest.TestCase类下面的各种断言方法用于对测试结果的判断
- #可定义多个测试用例
- def test_add(self):
- """Test method add(a, b)"""
- print "add"
- self.assertEqual(3, add(1, 2))
- self.assertNotEqual(3, add(2, 2))
- def test_minus(self):
- """Test method minus(a, b)"""
- print "minus"
- self.assertEqual(1, minus(3, 2))
- @unittest.skip("I don't want to run this case.") #装饰器,表明不再执行下个模块
- def test_multi(self):
- """Test method multi(a, b)"""
- print "multi"
- self.assertEqual(6, multi(2, 3))
- def test_divide(self):
- """Test method divide(a, b)"""
- print "divide"
- self.assertEqual(2, divide(6, 3))
- self.assertEqual(2.5, divide(5, 2))
- #常用于测试脚本是否能够正常运行
- if __name__ == '__main__':
- #unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们。
- #执行顺序是命名顺序:先执行test_case1,再执行test_case2,verbosity参数可以控制输出的错误报告的详细程度,默认1,0则不输出结果,2则输出详细结果
- unittest.main(verbosity=2)
第二步:组合测试用例:
- # -*- coding: utf-8 -*-
- import unittest
- from test_mathfunc import TestMathFunc
- if __name__ == '__main__':
- suite = unittest.TestSuite()
- tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")]
- suite.addTests(tests)
- runner = unittest.TextTestRunner(verbosity=2)
- runner.run(suite)
- #方式二:
- # 直接用addTest方法添加单个TestCase
- suite.addTest(TestMathFunc("test_multi"))
- # 用addTests + TestLoader
- # loadTestsFromName(),传入'模块名.TestCase名'
- suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc'))
- suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_mathfunc.TestMathFunc'])) # loadTestsFromNames(),类似,传入列表
- # loadTestsFromTestCase(),传入TestCase
- suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
第三步:运行测试用例并保存报告:
- # -*- coding: utf-8 -*-
- import unittest
- from test_mathfunc import TestMathFunc
- if __name__ == '__main__':
- suite = unittest.TestSuite()
- suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
-
- #写入TXT
- with open('UnittestTextReport.txt', 'a') as f:
- runner = unittest.TextTestRunner(stream=f, verbosity=2)
- runner.run(suite)
- #写入HTML:
- with open('HTMLReport.html', 'w') as f:
- runner = HTMLTestRunner(stream=f,
- title='MathFunc Test Report',
- description='generated by HTMLTestRunner.',
- verbosity=2
- )
- runner.run(suite)
最后,总结一波:
- unittest是Python自带的单元测试框架,我们可以用其来作为我们自动化测试框架的用例组织执行框架。
- unittest的流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。
- 一个class继承unittest.TestCase即是一个TestCase,其中以 test 开头的方法在load时被加载为一个真正的TestCase。
- verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告。
- 可以通过addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。
- 用 setUp()、tearDown()、setUpClass()以及 tearDownClass()可以在用例执行前布置环境,以及在用例执行后清理环境
- 我们可以通过skip,skipIf,skipUnless装饰器跳过某个case,或者用TestCase.skipTest方法。
- 参数中加stream,可以将报告输出到文件:可以用TextTestRunner输出txt报告,以及可以用HTMLTestRunner输出html报告。
参考文献:
https://blog.csdn.net/huilan_same/article/details/52944782
https://www.cnblogs.com/yufeihlf/p/5707929.html