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

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

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

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

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()
View Code

 

(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()
View Code

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 加入容器中执行

unittest.Testsuite()是测试套件对象
suite.addTest(testcase class(方法名))可以逐个添加想要运行的testcase至测试套件
suite.addTests()可以添加一个testcase的列表至测试套件
suite.addTest(testcase class)这里还可以添加testcase class,但是必须在testcase class中定义一个runTest方法
 
unittest.makesuite(testcase class)可以直接创建一个测试套件
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)
    #写入文件保存
View Code
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")
)
View Code

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)
View Code

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

 

posted @ 2021-01-23 15:17  镜轩思雨  阅读(168)  评论(0)    收藏  举报