python测试框架之unittest
官方文档:https://docs.python.org/zh-cn/3/library/unittest.html
翻译文档:https://blog.csdn.net/ljl6158999/article/details/80994979
1.unittest 结构

import unittest print(dir(unittest))
''' ['BaseTestSuite', 'FunctionTestCase', 'IsolatedAsyncioTestCase', 'SkipTest', 'TestCase', 'TestLoader',
'TestProgram', 'TestResult', 'TestSuite', 'TextTestResult', 'TextTestRunner',
'_TextTestResult', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__unittest',
'addModuleCleanup', 'async_case', 'case', 'defaultTestLoader', 'expectedFailure', 'findTestCases', 'getTestCaseNames', 'installHandler',
'load_tests', 'loader', 'main', 'makeSuite', 'registerResult', 'removeHandler', 'removeResult', 'result', 'runner', 'signals', 'skip',
'skipIf', 'skipUnless', 'suite', 'util']
'''
test fixture
A test fixture represents the preparation needed to perform one or more tests, and any associated cleanup actions. This may involve, for example, creating temporary or proxy databases, directories, or starting a server process.
test case
A test case is the individual unit of testing. It checks for a specific response to a particular set of inputs. unittest provides a base class, TestCase, which may be used to create new test cases.
test suite
A test suite is a collection of test cases, test suites, or both. It is used to aggregate tests that should be executed together.
test runner
A test runner is a component which orchestrates the execution of tests and provides the outcome to the user. The runner may use a graphical interface, a textual interface, or return a special value to indicate the results of executing the tests.
(1) TestFixture:翻译过来是测试固定装置的意思。形象的说,把整个测试过程看作大的装置,这个装置里不仅具有测试执行部件,还有测试之前环境准备和测试之后环境清理的部件,有机的结合起来就是一个更大的测试装置,即test fixture。简单来说就是做一些测试过程中需要准备的东西,比如创建临时的数据库,文件和目录等,其中setUp()和setDown()是最常用的方法。
- setup():每个测试函数运行前运行
- teardown():每个测试函数运行完后执行
- setUpClass():必须使用@classmethod 装饰器,所有test运行前运行一次
- tearDownClass():必须使用@classmethod装饰器,所有test运行完后运行一次
(2) TestCase:测试用例,注意与前面的TestCase类不是同一个概念。一个完整的测试流程就是一个测试用例,通过一些特定的输入得到响应,并对响应进行校验的过程。我们通过去继承TestCase这个父类,可以创建新的测试用例。用户自定义的测试case的基类,调用run()方法,会依次调用setUp方法、执行用例的方法、tearDown方法。
unittest.TestCase:TestCase类,所有测试用例类继承的基本类。
TestCase下的assert断言
1 self.fail(msg=None) 2 3 self.assertFalse(expr, msg=None) 4 self.assertTrue(expr, msg=None) 5 6 self.assertEqual(first, second, msg=None) 7 self.assertNotEqual(first, second, msg=None) 8 9 self.assertIn(member, container, msg=None) 10 self.assertNotIn(member, container, msg=None) 11 12 self.assertIs(expr1, expr2, msg=None) 13 self.assertIsNot(expr1, expr2, msg=None) 14 self.assertIsNone() 15 self.assertIsNotNone() 16 self.assertIsInstance() 17 self.assertNotIsInstance() 18 19 self.assertAlmostEqual() 20 self.assertNotAlmostEqual() 21 self.assertSequenceEqual() 22 self.assertListEqual() 23 self.assertTupleEqual() 24 self.assertSetEqual() 25 self.assertDictEqual() 26 self.assertDictContainsSubset() 27 self.assertCountEqual() 28 self.assertMultiLineEqual() 29 self.assertLess() 30 self.assertLessEqual() 31 self.assertGreater() 32 self.assertGreaterEqual() 33 self.assertRaisesRegex() 34 self.assertWarnsRegex() 35 self.assertRegex() 36 self.assertNotRegex() 37 38 self.assertRaises() 39 self.assertWarns() 40 self.assertLogs()
(3) TestSuite:测试套件,也称为测试集合。多个测试用例组合在一起就形成了测试集,当然测试集里不仅能包含测试用例,也可以再次嵌套测试集,测试集可以用于代码的组织和运行。测试用例集合,可以通过addTest()方法手动增加Test Case,也可以通过TestLoader自动添加Test Case,TestLoader在添加用例时,会没有顺序。
unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的。
addTest(): addTest()方法是将测试用例添加到测试套件中
(4)TestRunner:是Unittest中的重要组成部分,主要职责为执行测试,通过图形、文本或者返回一些特殊值的方式来呈现最终的运行结果。例如执行的用例数、成功和失败的用例数。运行测试用例的驱动类,可以执行TestCase,也可以执行TestSuite,执行后TestCase和TestSuite会自动管理TESTResult。
unittest.TextTextRunner():unittest框架的TextTextRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。
整个的流程就是首先要写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TestTestRunner来运行TestSuite,运行的结果保存在TextTestReusult中,整个过程集成在unittest.main模块中
2.执行方法
2.1 unittest.main()
1 import unittest
2
3 class TestClass(unittest.TestCase):
4 def setUp(self):
5 print("setUp")
6
7 def tearDown(self):
8 print("tearDown")
9
10 @classmethod
11 def setUpClass(cls):
12 print("setUpClass")
13
14 @classmethod
15 def tearDownClass(cls):
16 print("tearDownClass")
17
18 def test1(self):
19 a = 1
20 b = 2
21 self.assertEqual(a, b, "")
22
23 def test2(self):
24 a = True
25 self.assertTrue(a)
26
27
28 if __name__ == '__main__':
29 unittest.main()
1. 导入unittest模块
2. 实现Test开头的类,继承 unittest.TestCase
3. 定义的测试方法用 test开头
4.使用unittest.main() 执行测试用例
main.py是unittest主文件 ==》main方法,实际是 TestProgram 类
https://blog.csdn.net/qq_37023538/article/details/69159928
调用过程:
TestProgram.__init__() ==> TestProgram.parseArgs() ==> TestProgram.createTests() ==> TestProgram.runTests()
__init__() 初始化调用parseArgs()和runTests()
parseArgs()解析输入参数
createTests()创建测试用例集合
runTests()执行测试用例
2.2 TestSuite 加入容器中执行
suite.addTest(testcase class(方法名))可以逐个添加想要运行的testcase至测试套件
suite.addTests()可以添加一个testcase的列表至测试套件
suite.addTest(testcase class)这里还可以添加testcase class,但是必须在testcase class中定义一个runTest方法
unittest.TestLoader().loaderTestsFromTestCase(testcase classs)从指定的testcase class类构建一个测试套件
unittest.TextTestRunner()创建一个运行器
runer.run(suite)运行指定的测试套件
suite.countTestCases()返回测试套件中的case数
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test.py')这个方法可以去test_dir目录下查找以test开头的.py文件,并自动加载这些test.py中的testcase class生成一个测试套件
suite=unittest.TestSuite() suite.addTest(TestClass("test1")) suite.addTest(TestClass("test2"))
unittest.TextTestRunner().run(suite)
2.3 TestLoader
unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(test*.py),并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover。
suite1 = unittest.TestLoader().loadTestsFromTestCase(TestClass)
suite = unittest.TestSuite([suite1,])
unittest.TextTestRunner().run(suite)
2.4 通过 discover 方式加载某路径下的所有测试用例
###
import unittest
discover 可以一次调用多个脚本
test_dir 被测试脚本的路径
pattern 脚本名称匹配规则
test_dir = "./test_case"
discover = unittest.defaultTestLoader.discover(test_dir, pattern="test*.py")
匹配 test_case 目录下所有以 test 开头的 py 文件,执行这些 py 文件下的所有测试用例
if name == "main":
runner=unittest.TextTestRunner()
runner.run(discover)
2.5 通过命令行执行
python -m unittest -h 帮助
python -m unittest 文件名.模块名.用例名
2.6 带测试报告
HTMLTestRunner是Python标准库的unittest模块的扩展。它生成易于使用的HTML测试报告。
#加入测试报告,执行所有case
unittest.main(testRunner=HtmlTestRunner.HTMLTestRunner(output='example_dir'))
#输出txt
import unittest
if __name__ == "__main__":
# 测试用例目录
test_dir = r"D:\Git\Test_Framework\test_case"
# 加载测试用例
discover = unittest.defaultTestLoader.discover(test_dir, 'test*.py')
# 测试报告路径
report_path = r"D:\Git\Test_Framework\report\report.text"
with open(report_path,"a") as report:
runner = unittest.TextTestRunner(stream=report,verbosity=2)
runner.run(discover)
#加入测试报告,执行加入容器的case
import unittest
from HTMLTestRunner import HTMLTestRunner
if __name__ == "__main__":
# 测试用例目录
test_dir = r"D:\Git\Test_Framework\test_case"
# 加载测试用例
discover = unittest.defaultTestLoader.discover(test_dir, 'test*.py')
# 测试报告路径
report_path = r"D:\Git\Test_Framework\report\report.html"
with open(report_path,"wb") as report:
runner = HTMLTestRunner(stream = report,
title = "测试报告",
description = "系统登录测试用例执行")
runner.run(discover)
1 suite = unittest.TestSuite()
2 suite.addTest(TestMethod("test_01"))
3 suite.addTest(TestMethod("test_02"))
4 suite.addTest(TestMethod("test_03"))
5 testRunner=HtmlTestRunner.HTMLTestRunner(output='example_dir')
6 testRunner.run(suite)
7 #################################################################
8 # 输出到文件
9 fp = file('my_report.html', 'wb')
10 runner = HTMLTestRunner.HTMLTestRunner(
11 stream=fp,
12 title='My unit test',
13 description='This demonstrates the report output by HTMLTestRunner.'
14 )
15
16 # 使用外部样式表。
17 # 运行测试
18 runner.run(my_test_suite)
# 其他报告模块
1) BeautifulReport
pip install BeautifulReport
import unittest
from BeautifulReport import BeautifulReport
# 用例存放位置,把放用例的地址填上去填到用例的文件夹
test_case_path="..\TestCase"
# 用来测试报告存放位置
report_path='..\Report'
# 自定义测试报告名称
filename='测试报告'
#html里面报告汇总用例的名称
description='简单测试'
# 需要执行哪些用例,如果目录下的全部,可以改为"*.py",如果是部分带test后缀的,可以改为"*test.py"
#我这里运行全部的测试用例
pattern="*.py"
if __name__ == '__main__':
test_suite = unittest .defaultTestLoader.discover(test_case_path, pattern=pattern)
#unittest的一个方法,智能获取文件下面的case去跑
result = BeautifulReport(test_suite)
#只能绘制图表
result.report(filename=filename,description=description,report_dir=report_path)
#写入文件保存
2) hwtestreport
https://www.zhwei.cn/hwttk-unittest-hwtestreport/
3)HTMLTestRunnerCN
https://github.com/findyou/HTMLTestRunnerCN
3.跳过测试
unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是比如说想调试某一个测试用例,想先屏蔽其他用例就可以用装饰器屏蔽。
@unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。
@unittest.skipIf(reason): skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。
@unittest.skipUnless(reason): skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的原因。
@unittest.expectedFailure(): expectedFailure()测试标记为失败。
4.参数化
4.1 paramunittest
安裝:pip install paramunittest
1.官方文档地址:https://pypi.python.org/pypi/ParamUnittest/
2.github源码下载地址:https://github.com/rik0/ParamUnittest
import unittest import paramunittest # 方案一 @paramunittest.parametrized( ('1', '2'), #(4, 3), ('2', '3'), (('4', ), {'b': '5'}), ((), {'a': 5, 'b': 6}), {'a': 5, 'b': 6}, ) class TestFoo(paramunittest.ParametrizedTestCase): def setParameters(self, a, b): self.a = a self.b = b def testLess(self): self.assertLess(self.a, self.b) # 方案二 @paramunittest.parametrized( ('1', '2'), #(4, 3), ('2', '3'), (('4', ), {'b': '5'}), ((), {'a': 5, 'b': 6}), {'a': 5, 'b': 6}, ) class TestBar(unittest.TestCase): def setParameters(self, a, b): self.a = a self.b = b def testLess(self): self.assertLess(self.a, self.b) if __name__ == "__main__": unittest.main(verbosity=2) 实践案例 1.从上面官方文档给的案例可以看出,参数可以传元组也可以传字典,先传字典参数,类似于如下这种一组参数: {"user": "admin", "psw": "123", "result": "true"} 2.注意这里接受参数的时候,必须要定义setParameters这个方法,并且只能是这个名称。括号后面的参数分别接受传入的参数名称。前面定义的是字典,那参数就跟前面字典的key保持一致 import unittest import paramunittest import time @paramunittest.parametrized( {"user": "admin", "psw": "123", "result": "true"}, {"user": "admin1", "psw": "1234", "result": "true"}, {"user": "admin2", "psw": "1234", "result": "true"}, {"user": "admin3", "psw": "1234", "result": "true"}, {"user": "admin4", "psw": "1234", "result": "true"}, {"user": "admin5", "psw": "1234", "result": "true"}, {"user": "admin6", "psw": "1234", "result": "true"}, {"user": "admin7", "psw": "1234", "result": "true"}, {"user": "admin8", "psw": "1234", "result": "true"}, {"user": "admin9", "psw": "1234", "result": "true"}, {"user": "admin10", "psw": "1234", "result": "true"}, {"user": "admin11", "psw": "1234", "result": "true"}, ) class TestDemo(unittest.TestCase): def setParameters(self, user, psw, result): '''这里注意了,user, psw, result三个参数和前面定义的字典一一对应''' self.user = user self.user = psw self.result = result def testcase(self): print("开始执行用例:--------------") time.sleep(0.5) print("输入用户名:%s" % self.user) print("输入密码:%s" % self.user) print("期望结果:%s " % self.result) time.sleep(0.5) self.assertTrue(self.result == "true") if __name__ == "__main__": unittest.main(verbosity=2) #5.除了传字典参数,传元组类型的也是可以的 @paramunittest.parametrized( ("admin", "123", "true"), ("admin1", "123", "true"), ("admin2", "123", "true"), ("admin3", "123", "true"), ("admin4", "123", "true"), ("admin5", "123", "true"), ("admin6", "123", "true"), ("admin7", "123", "true"), ("admin8", "123", "true"), ("admin9", "123", "true"), ("admin10", "123", "true"), ("admin11", "123", "true"), ("admin12", "123", "true") )
4.2 parameterized
安裝:pip install parameterized
from parameterized import parameterized,param import unittest def add(a,b): return a+b class AddTest(unittest.TestCase): @parameterized.expand([ param(1,1,2), param(1.0,1.0,2.0), param('hi',' wuya','hi wuya') ]) def test_add_cases(self,first,second,result): self.assertEqual(add(first,second),result) if __name__ == '__main__': unittest.main(verbosity=2)
4.3 ddt
1.官方文档: https://ddt.readthedocs.io/en/latest/
5.mock
官方文档:https://docs.python.org/zh-cn/3/library/unittest.mock.html
from unittest import mock

浙公网安备 33010602011771号