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()
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  镜轩思雨  阅读(201)  评论(0)    收藏  举报