unittest单元测试框架

Unittest

一、unittest简介

可查看官方文档:https://docs.python.org/zh-cn/3/library/unittest.html#module-unittest

unittest是受Java中的JUnit的启发,针对于Python语言而推出的一种单元测试框架。有如下一些优点:
1、支持测试自动化,配置共享和机关代码测试
2、支持将测试样例聚合到测试集中,并将测试与报告框架独立。一般会调用测试函数,调用测试函数可以聚合所有的测试结果并产生结果报告
3、支持面向对象概念,有四个重要概念:测试脚手架(test fixture)、测试用例(test case)、
测试套件(test suit)、测试运行器(test runner)
测试脚手架:表示为了开展一箱货多项测试所需要进行的准备工作,以及所有相关的清理操作,每个测试用例运行时都会调用一次setUp()、tearDown()、init()
测试用例:一个独立的测试单元,检查输入特定的数据时的响应,需要继承unittest提供的基类:TestCase
测试套件:一系列的测试用例或者测试套件,或者测试用例与测试套件的混合,用于归档需要一起执行的测试
测试运行器:用于执行和输出测试结果的组件

二、unittest的基本使用

命名规则

方法的命名都以test开头,这个命名约定告诉测试运行者类的那些方法表示测试

setup和tearDown

def setUp():
        # 每个测试用例运行前运行
        ...
    def tearDown():
        # 每个测试用例运行后运行
        ...
    @classmethod
    def setUpClass(cls):
        # 在一个类中的所有用例执行之前运行的
        ...
    @classmethod
    def tearDownClass(cls):
        # 在一个类中的所有用例都执行完之后运行的

函数调用

检查预期的输出:assertEqual()
验证条件:assertTrue()、assertFalse()、assertAlmostEqual()、
assertAlmostEquals()、assertCountEqual()、assertDictContainsSubset()、
assertDictEqual()、assertGreater()、assertGreaterEqual()、assertIn()、assertIs()、
assertIsInstance()、assertIsNone()、assertIsNot()、assertIsNotNone()、assertLess()、
assertLessEqual()、assertListEqual()、assertLogs()、assertMultiLineEqual()、assertNotAlmostEqual()、
assertNotAlmostEquals()、assertNotEqual()、assertNotEquals()、assertNotIn()、assertNotIsInstance()、
assertNotRegex()、assertNotRegexpMatches()、assertRegex()、assertRegexpMatches()、assertSequenceEqual()、
assertSetEqual()、assertTupleEqual()、
抛出异常:assertRaiseRegex()、assertRaiseRegexp()、assertWarns()、assertWarnsRegex()

命令行接口

通过主函数运行测试用例:

 if __name__ == '__main__':
            unittest.main()

​ 在终端直接调用测试用例:
​ 运行独立模块:

python -m unittest test_module01

​ 运行测试类:

python -m unittest test_module01.testClass01

​ 运行某个测试类下的测试方法:

python -m unittest test_module01.testClass01.test_01

​ 通过文件路径指定:

python -m unittest test_module01/testClass01.py

​ 探索性测试:
​ -v : 更详细地输出结果
​ -s : 开始进行搜索的目录(默认值为当前目录)
​ -p : 用于匹配测试文件的模式
​ -t : 指定项目的最上层目录(通常为开始时所在目录)
​ eg: 运行test_module01中的所有以_o1结尾的测试用例:

 pyton -m unittest -s test_module01 -p *_o1.py
python -m unittest -s test_module01.testClass01 -p *_01.py

测试套件

自定义测试套件

 fp=file(filename,'wb')
 def suite(self):
	# 构造测试集,实例化测试套件
    suit = unittest.TestSuite()
    # 将测试用例加载到测试套件中,执行顺序是安装加载顺序:先执行test_02,再执行test_01
    suit.addTest(Test('test_02'))
    suit.addTest(Test('test_01'))
    return suite
if __name__ == '__main__':
    # unittest.main('-v')
    # 实例化TextTestRunner类
    # 可导入HTMLTestRunner包输出更详细的报告 runner=HTMLTestRunner.HTMLTestRunner(stream=fp,title=u'Atest测试用例执行',description=u'测试结果:') 结尾需要fp.close()
    runner = unittest.TextTestRunner()
    # 运行测试套件(运行测试套件中的所有用例
    runner.run(suite())

构造测试集:执行顺序是命名顺序

test_dir = './'
discover = unittest.defaultTestLoader.discover(test_dir,pattern='test_*.py')
# 执行测试用例,实例化TextTestRunner类
runner = unittest.TextTestRunner()
# 运行测试套件
runner.run(discover)

通过模块加载测试用例:

suit = unittest.TestSuite()
# 实例化用力加载器
loader = unittest.TestLoader()
# 添加测试模块
suite.addTest(loader.loadTestsFromeModule(测试模块名))

通过测试类加载测试用例:

suit = unittest.TestSuite()
# 实例化用力加载器
loader = unittest.TestLoader()
# 添加测试模块
suite.addTest(loader.loadTestsFromeTestCase测试模块名))

一个一个添加测试用例:

suite = unittest.TestSuite()
suite.addTest(测试类名('方法名'))

复用已有的测试代码

快速将现有的测试转换成基于unittest的测试—FunctionTestCase类(不推荐此方法)

# 采用FunctionTestCase类复用已有测试代码
def testSomething():
    something = makeSomethingValue()
    assert something is not None
def makeSomethingValue():
    something = 'test'
    return something
def initSomething():
    something = ''

testcase = unittest.FunctionTestCase(testSomething(),setUp=makeSomethingValue,tearDown=initSomething)

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(testcase)

跳过测试与预计失败

跳过测试适用场景:a、用例正在开发中,需要先执行其它用例 b、用例已经废弃,但是需要存档 c、某些条件下不需要执行该用例

预计失败适用场景:a、一些执行失败被认为通过测试的用例
三种跳过测试装饰器
@unittest.skip(‘reason’) --------->无条件跳过测试,reason为跳过的理由
@unittest.skipif(‘condition’,‘reason’) ----->当condition=True时跳过测试,reason为跳过的理由
@unittest.skipunless(‘condition’,‘reason’) —>当condition=False时跳过测试,reason为跳过的理由
一种预计失败装饰器:
@unittest.expectedFailure()

# @unittest.skip('跳过测试类')
class TestSkipCase(unittest.TestCase):
    # @unittest.skip(reason): 无条件跳过测试,reason描述为什么跳过测试
    @unittest.skip('tiaoguo')
    def test_nothing(self):
        self.fail("shouldn't happen !")

    @unittest.skipIf(1==2,'equal')
    def test_equal(self):
        pass
    @unittest.skipUnless(1==2,'dont equal')
    def tast_dont_equal(self):
        pass
    def test_myskip(self):
        if 1==2:
            self.skipTest('1 != 2')

 	@unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1,2,"1 !=2")
    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 1, "1==2")
if __name__ == '__main__':
    unittest.run(['-v','-s'],TestSkipCase)

子测试区分测试迭代

使用subTest(),输出每次迭代更详细的错误信息

class NumbersTest(unittest.TestCase):
    # 使用子测试
    def test_even(self):
        for i in range(0, 6):
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)
    # 未使用子测试
    def test_even02(self):
        for i in range(0, 6):
            self.assertEqual(i % 2, 0)

输出报告

HTMLTestRunner报告

import HTMLTestRunner
#...
# 以二进制模式打开一个文件
f = open('test.html','wb')
runner = HTMLTestRunner.HTMLTestRunner(f,title='unittest用例标题',description='这是用例描述')
# 运行用例(用例集合)
runner.run(suite)
f.close()

BeautifulReport报告

from BeautifulReport import BeautifulReport as bf
# ...
# 实例化BeautifulReport模块
run = bf(suite)
run.report(filename='test',description='这个描述参数是必填的')

数据驱动(DDT)

简介:测试数据参数化
应用场景:一般进行接口测试时,每个接口的传参都不止一种情况,一般会考虑正向、逆向等多种组合。所以在测试一个接口时通常会编写多条case,而这些case除了传参不同外,其实并没什么区别。
这个时候就可以利用ddt来管理测试数据,提高代码复用率
安装:pip install ddt
四种引入模式:a、引入装饰器@ddt b、导入数据的@data c、拆分数据的@unpack d、导入外部数据的@file_data

@ddt
class TestDDT01(unittest.TestCase):
    # ====================读取元组======================
    # 单组元素
    @data(1,2,3)
    def test01(self,value):
        print(value)

    # 未拆分多组元素
    @data((1,2,3),(4,5,6))
    def test02(self,value):
        print(value)

    # 拆分多组元素
    @data((1,2,3),(4,5,6))
    @unpack
    def test03(self,value1,value2,value3):
        print(value1,value2,value3)

    # ==================读取列表=========================
    # 多组元素未分解
    @data([{'name':'hahah','age':12},{'name':'heheh','age':18}])
    def test04(self,value):
        print(value)

    # 多组元素分解
    @data([{'name':'hahah','age':12},{'name':'heheh','age':18}])
    @unpack
    def test05(self,value1,value2):
        print(value1,value2)

    # ===================读取字典数========================
    # 多组元素未分解
    @data({'name': 'hahah', 'age': 12}, {'name': 'heheh', 'age': 18})
    def test06(self, value):
        print(value)

    # 多组数据拆分
    @data({'name': 'hahah', 'age': 12}, {'name': 'heheh', 'age': 18})
    @unpack
    # 在拆分的时候,形参和实参的key值要一致,否则就报错
    def test07(self, name, age):
        # 结果展示的数据是字典里的value,不会打印key的值
        print(name,age)

    # ===================读取文件数据========================
    testdata = [{'a': 'lili', 'b': 12}, {'a': 'sasa', 'b': 66}]
    @data(*testdata)
    # @unpack
    def test08(self, value):
        print(value)

    @file_data('yaml/login.yaml')
    def test10(self,**kwargs):
        print(kwargs.get('url'))

三、unittest的API简介

断言函数

  • assertEqual(a,b,msg=None) 判断 a == b

  • assertNotqual(a,b,msg=None) 判断 a!=b

  • assertTrue(x,msg=None) 判断 bool(x) = True

  • assertFlase(x,msg=None) 判断 bool(x) = Flase

  • assertIs(a,b,msg=None) 判断 a is b , 包括对象

  • assertIsNone(x,msg=None) 判断 x is None

  • assertIsNotNone(x,msg=None) 判断 x is not None

  • assertIn(a,b,msg=None) 判断 a in b

  • assertNotIn(a,b,msg=None) 判断 a not in b

  • assertIsInstance(a,b,msg=None) 判断 isinstance(a,b)

  • assertNotIsInstance(a,b,msg=None) 判断(对象类型) not isinstance(a,b)

  • assertRaises(exc,fun,*args,**kwds) 判断fun(*args,*kwds) raises exc
    解析:测试在使用任何位置或关键字参数调用callable时是否引发异常,这些参数也传递给assertRaises()。
    如果引发异常,则测试通过;如果引发另一个异常,则测试出错;如果未引发异常,则测试失败。要捕获一组异常中的任何一个,
    可以将包含异常类的元组作为异常传递

  • assertRaises(exception,msg=None) 返回一个上下文管理器
    解析:如果只给出了异常和可能的msg参数,则返回一个上下文管理器(上下文管理器将捕获的异常对象存储在其异常属性中),
    以便测试中的代码可以内联编写,而不是作为函数编写
    eg:

 class TestAssertError(unittest.TestCase):
        def do_something(self):
            with self.assertRaises(ZeroDivisionError,1/0) as cm:
                print('error')
            the_exception = cm.exception
            self.assertEqual(the_exception.error_code, 3)
            
        def test_args_must_match_init(self):
            self.assertRaises(ZeroDivisionError,1/0 )
  • assertRaiseRegex(exc,r,fun,args,kwds) 判断fun(args,kwds) raises exc and the message matches regex r
    解析:与assertRaises()类似,但也测试正则表达式是否与引发的异常的字符串表示形式匹配。正则表达式可以是正则表达式对象,
    也可以是包含适合re使用的正则表达式的字符串
    eg:
self.assertRaisesRegex(ValueError, "invalid literal for.XYZ'$",
                       int, 'XYZ')
with self.assertRaisesRegex(ValueError, 'literal'):
                int('XYZ')
  • assertWarns(warn,fun,args,kwds) 判断fun(args,kwds) raises warn

解析:测试在使用任何位置或关键字参数(也传递给AssertWarnings())调用callable时是否触发警告。
如果触发警告,则测试通过;如果未触发警告,则测试失败。任何异常都是错误。要捕获一组警告中的任何一个,可以将包含警告类的元组作为警告传递

  • assertWarns(warning, *, msg=None) 返回一个上下文管理器
    解析:如果只给出了警告和可能的msg参数,则返回上下文管理器(上下文管理器将捕获的异常对象存储在其异常属性中),以便测试中的代码可以内联编写,而不是作为函数编写
    eg:
 with self.assertWarns(SomeWarning) as cm:
                do_something()
 self.assertIn('myfile.py', cm.filename)
 self.assertEqual(320, cm.lineno)
  • assertWarnsRegex(warn,r,fun,*args,**kwds) 判断fun(*args,**kwds) raises warn and the message matches regex r
  • assertWarnsRegex(warning, regex, *, msg=None)
    解析:与AssertWarnings()类似,但也测试正则表达式是否与触发的警告消息匹配。正则表达式可以是正则表达式对象,也可以是包含适合re使用的正则表达式的字符串
    eg:
 self.assertWarnsRegex(DeprecationWarning,
                      r'legacy_function\(\) is deprecated',
                      legacy_function, 'XYZ')
 with self.assertWarnsRegex(RuntimeWarning, 'unsafe frobnicating'):
    frobnicate('/etc/passwd')
  • assertLogs(Logger,level) 日志记录器上记录了至少一条消息,如果with块内发出的至少一条消息与记录器和级别条件匹配,则测试通过,否则测试失败
    解析:一种上下文管理器,用于测试记录器或其子项上是否至少记录了一条消息,且至少具有给定的级别;如果给定Logger,记录器应该是日志记录。
    Logger对象或提供记录器名称的str。默认为根记录器,它将捕获未被非传播后代记录器阻止的所有消息;如果给定level,级别应该是数字日志级别或
    其等效字符串(例如“ERROR”或logging.ERROR)。默认设置是日志记录。
    上下文管理器返回的对象是一个记录助手,它跟踪匹配的日志消息。它有两个属性:records(日志记录列表)、output(具有匹配消息格式化输出的str对象列表)
    eg:
 with self.assertLogs('foo', level='INFO') as cm:
               logging.getLogger('foo').info('first message')
               logging.getLogger('foo.bar').error('second message')
 self.assertEqual(cm.output, ['INFO:foo:first message',
                                         'ERROR:foo.bar:second message'])
  • assertNoLogs(logger,level) 判断日志记录器上不会纪录最低级别的块日志(上下文管理器不会返回任何内容)

  • assertAlmostEqual(a,b) 判断round(a-b,7) == 0
    解析:通过计算差值,四舍五入到给定的小数位数(默认为7),并与零进行比较,测试第一个和第二个是否近似相等。请注意,这些方法将值四舍五入到给定的小数位数

  • assertNotAlmostEqual(a,b) 判断round(a-b,7) != 0

  • assertGreater(a,b) 判断a > b

  • assertGreaterEqual(a,b) 判断a >= b

  • assertLess(a,b) 判断a < b

  • assertLessEqual(a,b) 判断a <= b

  • assertRegex(s,r) 判断r.search(s)

  • assertNotRegex(s,r) 判断 not r.search(s)

  • assertCountEqual(a,b) 判断a与b有相同的元素,验证两个序列中的每个元素是否具有相同的计数,如果没有,将生成一条错误消息,列出序列之间的差异

测试组

unittest.TestSuit(tests=()) 用于将测试聚合到应该一起运行的测试组中

  • addTest(test) 添加一个测试用例或测试套件到suit中
  • addTests(tests) 将TestCase和TestSuite实例的iterable中的所有测试添加到此测试套件,相当于迭代测试,为每个元素调用addTest()
  • run(result) 运行与此套件关联的测试,将结果收集到作为结果传递的测试结果对象中。注意,与TestCase不同。TestSuite.run()要求传入结果对象
  • debug() 运行与此套件关联的测试,但不收集结果。这允许将测试引发的异常传播到调用方,并可用于支持在调试器下运行测试
  • countTestCases() 返回此测试对象表示的测试数,包括所有单个测试和子套件
    iter()

加载和运行测试

  • unittest.TestLoader TestLoader类用于从类和模块创建测试套件。通常,不需要创建此类的实例;unittest模块提供了一个可以作为unittest共享的实例:defaultTestLoader 但是,使用子类或实例可以自定义某些可配置属性

  • loadTestsFromTestCase(testCaseClass) 返回TestCase派生的TestCase类中包含的所有测试用例的套件

  • loadTestsFromModule(module, pattern=None) 返回给定模块中包含的所有测试用例的套件。此方法在模块中搜索从TestCase派生的类,并为该类定义的每个测试方法创建该类的实例
    适用于:当装置不同并且在子类中定义时

  • loadTestsFromName(name, module=None) 返回一组给定字符串说明符的所有测试用例

  • loadTestsFromNames(names, module=None) 与loadTestsFromName()类似,但采用名称序列而不是单个名称。返回值是一个测试套件,它支持为每个名称定义的所有测试

  • getTestCaseNames(testCaseClass) 返回在testCaseClass中找到的方法名的排序序列

  • discover(start_dir, pattern=‘test*.py’, top_level_dir=None) 通过从指定的开始目录递归到子目录来查找所有测试模块,并返回包含它们的TestSuite对象,所有测试模块必须可从项目顶层导入。如果开始目录不是顶级目录,则必须单独指定顶级目录,start_dir可以是虚线模块名,也可以是目录

  • TestLoader的以下属性可以通过子类化或实例赋值进行配置
    testMethodPrefix 给出将被解释为测试方法的方法名称的前缀。默认值为“test”,会影响getTestCaseNames()和所有loadTestsFrom*()方法
    sortTestMethodsUsing 用于在getTestCaseNames()和所有loadTestsFrom*()方法中对方法名进行排序时比较方法名
    suiteClass 从测试列表构造测试套件的可调用对象。结果对象上不需要任何方法。默认值是TestSuite类
    testNamePatterns Unix shell样式通配符测试名称模式的列表,测试方法必须匹配这些模式才能包含在测试套件中

  • unittest.TestResult 用于编译有关哪些测试成功,哪些测试失败的信息(TestResult对象存储一组测试的结果,TestCase和TestSuite类确保正确记录结果)
    errors 错误,包含2元组的TestCase实例和包含格式化回溯的字符串的列表。每个元组表示引发意外异常的测试
    failures 失败,包含2元组的TestCase实例和包含格式化回溯的字符串的列表。每个元组表示一个测试,其中使用TestCase显式通知失败。断言*()方法
    skipped 跳过,包含2元组的TestCase实例和字符串的列表,其中包含跳过测试的原因
    expectedFailures 预期的失败,包含2元组的TestCase实例和包含格式化回溯的字符串的列表。每个元组表示测试用例的预期失败或错误
    unexpectedSuccesses 意外的成功,包含标记为预期失败但成功的TestCase实例的列表
    shouldStop 应该停止,当测试的执行应按stop()停止时,设置为True
    testsRun 测试运行,到目前为止运行的测试总数
    buffer 缓冲器,如果设置为true,则为sys。标准输出和系统。stderr将在调用的startTest()和stopTest()之间缓冲。
    收集的输出将仅回显到实际系统上。标准输出和系统。如果测试失败或出现错误,则返回stderr。任何输出也会附加到故障/错误消息
    failfast 失败,如果设置为true,将在第一次失败或错误时调用stop(),从而停止测试运行
    tb_locals 如果设置为true,则局部变量将显示在回溯中
    wasSuccessful() 如果到目前为止运行的所有测试都已通过,则返回True,否则返回False
    stop() 通过将shouldStop属性设置为True,可以调用此方法来发出信号,表明正在运行的测试集应该中止,
    例如,TextTestRunner类使用此功能在用户从键盘发出中断信号时停止测试框架。提供TestRunner实现的交互式工具可以以类似的方式使用它

  • startTest(test) 当测试用例测试即将运行时调用

  • stopTest(test) 在执行测试用例测试后调用,无论结果如何

  • startTestRun() 在执行任何测试之前调用一次

  • stopTestRun() 在执行所有测试后调用一次

  • addError(test, err) 当测试用例测试引发意外异常时调用。err是sys返回的形式的元组。exc_info():(类型、值、回溯),
    默认实现将一个元组(test,formatted_err)附加到实例的errors属性,其中formatted_err是从err派生的格式化回溯

  • addFailure(test, err) 当测试用例测试发出失败信号时调用。err是sys返回的形式的元组。exc_info():(类型、值、回溯)
    默认实现将一个元组(test,formatted_err)附加到实例的failures属性,其中formatted_err是从err派生的格式化回溯

  • addSuccess(test) 当测试用例测试成功时调用,默认实现不执行任何操作

  • addSkip(test, reason) 在跳过测试用例测试时调用。原因是测试给出的跳过的原因.默认实现将一个元组(test、reason)附加到实例的skipped属性

  • addExpectedFailure(test, err) 当测试用例测试失败或出现错误时调用,但标记为expectedFailure()decorator
    默认实现将一个元组(test,formatted_err)附加到实例的expectedFailures属性,其中formatted_err是从err派生的格式化回溯

  • addUnexpectedSuccess(test) 当测试用例测试标记为expectedFailure()decorator但成功时调用,默认实现将测试附加到实例的unexpectedsuccessions属性

  • addSubTest(test, subtest, outcome) 当子测试完成时调用。test是与测试方法相对应的测试用例。subtest是描述子测试的自定义测试用例实例,如果结果为“无”,则子测试成功。否则,它将失败,出现一个异常,其中结果是sys返回的形式的元组。exc_info():(类型、值、回溯)

  • unittest.TextTestResult(stream, descriptions, verbosity) 使用的TestResult的具体实现

  • unittest.defaultTestLoader 要共享的TestLoader类的实例。如果不需要定制TestLoader,则可以使用该实例,而不是重复创建新实例

  • unittest.TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, *, tb_locals=False)
    将结果输出到流的基本测试运行程序实现。如果stream为None,则默认值为sys。stderr用作输出流。这个类有几个可配置的参数,
    但本质上非常简单。运行测试套件的图形应用程序应该提供替代实现。这些实现应该接受**KWARG,因为当特性添加到unittest时,构建Runner的接口会发生变化

  • _makeResult() 此方法返回run()使用的TestResult实例

  • run(test) 此方法是TextTestRunner的主要公共接口。此方法采用TestSuite或TestCase实例。通过调用_makeResult()创建TestResult,然后运行测试并将结果打印到stdout

  • unittest.main(module=‘main’, defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader,
    exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None, warnings=None)
    从模块加载一组测试并运行它们的命令行程序;这主要是为了使测试模块易于执行
    defaultTest 单个测试的名称,或要运行的测试名称的iterable(如果没有通过argv指定测试名称)。如果未指定,或者通过argv未提供None和测试名称,则运行模块中找到的所有测试
    argv参数可以是传递给程序的选项列表,第一个元素是程序名。如果未指定或无,则sys的值
    testRunner参数可以是测试运行程序类,也可以是已创建的实例。默认情况下,main调用sys
    exit(),其退出代码指示测试运行的成功或失败
    testLoader testLoader实例,默认为defaultTestLoader
    verbosity 输出更详细的信息

  • load_tests(loader, standard_tests, pattern) 模块或包可以通过实现名为load_tests的函数,自定义在正常测试运行或测试发现期间如何从它们加载测试,返回一个suit

eg:

test_cases = (TestCase1, TestCase2, TestCase3)
def load_tests(loader, tests, pattern):
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
        return suite
def load_tests(loader, standard_tests, pattern):
    # top level directory cached on loader instance
    this_dir = os.path.dirname(__file__)
    package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
    standard_tests.addTests(package_tests)
    return standard_tests

setUpClass and tearDownClass

eg:

import unittest
class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()
            
    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()

注:如果在setUpClass期间引发异常,则不会运行该类中的测试,也不会运行tearDownClass。跳过的类将不会运行setUpClass或tearDownClass。如果异常是SkipTest异常,则该类将被报告为已跳过,而不是错误

setUpModule and tearDownModule

eg:

def setUpModule():
        createConnection()
def tearDownModule():
    closeConnection()

注意:如果在setUpModule中引发异常,则不会运行该模块中的任何测试,也不会运行tearDownModule。如果异常是SkipTest异常,则模块将被报告为已跳过,而不是错误
要添加即使在异常情况下也必须运行的清理代码,使用unittest.addModuleCleanup(function, /, *args, **kwargs),添加要在tearDownModule()之后

信号处理

  • unittest.installHandler() 安装control-c处理程序。当信号响起时。接收到SIGINT(通常是响应用户按下control-c)时,所有注册的结果都会被调用stop()
  • unittest.registerResult(result) 注册TestResult对象以进行control-c处理。注册一个结果会存储对它的弱引用,因此它不会阻止结果被垃圾收集。
    如果未启用control-c处理,则注册TestResult对象不会产生任何副作用,因此测试框架可以无条件地注册它们创建的所有结果,而不管是否启用了处理
  • unittest.removeResult(result) 删除已注册的结果。删除结果后,将不再对该结果对象调用stop(),以响应控件c
  • unittest.removeHandler(function=None) 当在没有参数的情况下调用此函数时,如果已安装control-c处理程序,则会将其删除。此函数还可用作测试装饰器,以便在执行测试时临时删除处理程序
    eg:
 @unittest.removeHandler
 def test_signal_handling(self):
    ...

不常用函数方法

  • addTypeEqualityFunc(typeobj, function)
    解析:注册assertEqual()调用的特定于类型的方法,以检查两个类型完全相同的对象OBJ(不是子类)是否比较相等。
    函数必须采用两个位置参数和第三个msg=None关键字参数,就像assertEqual()一样。它必须提升自我。failureException(msg),
    当检测到前两个参数之间的不平等时——可能提供有用的信息,并在错误消息中详细解释不平等

  • assertMultiLineEqual(a, b) 测试第一个多行字符串是否等于第二个字符串。当不相等时,突出显示差异的两个字符串的差异将包含在错误消息中。将字符串与assertEqual()进行比较时,默认情况下使用此方法

  • assertSequenceEqual(a, b) 测试两个序列是否相等。如果提供了seq_类型,则第一个和第二个都必须是seq_类型的实例,否则将引发故障。如果序列不同,则构造一条错误消息,显示两者之间的差异。
    此方法不是由assertEqual()直接调用的,而是用于实现AssertListQual()和assertTupleEqual()

  • assertListEqual(a, b) 测试两个列表是否相等

  • assertTupleEqual(a, b) 测试两个元组是否相等

  • assertSetEqual(a, b) 测试两个集合是否相等

  • assertDictEqual(a, b) 测试两个字典是否相等

  • fail(msg=None) 无条件发出测试失败信号,错误消息为msg或None

  • failureException 该类属性给出测试方法引发的异常。如果一个测试框架需要使用一个专门的异常,可能是为了携带额外的信息,
    那么它必须将这个异常子类化,以便与框架“公平竞争”。此属性的初始值为AssertionError

  • longMessage 此class属性确定将自定义失败消息作为msg参数传递给失败的assertXYY调用时发生的情况。True是默认值。
    在这种情况下,自定义消息将附加到标准故障消息的末尾。设置为False时,自定义消息将替换标准消息.
    通过分配实例属性self,可以在单个测试方法中重写类设置。longMessage,在调用assert方法之前设置为True或False

  • maxDiff 此属性通过在失败时报告差异的断言方法控制差异输出的最大长度。默认为80*8个字符。将maxDiff设置为None意味着没有最大长度的diff

  • countTestCases()

收集信息的methods

  • countTestCases() 返回此测试对象表示的测试数。对于TestCase实例,该值始终为1。
  • defaultTestResult() 返回应用于此测试用例类的测试结果类的实例(如果没有向run()方法提供其他结果实例)
    id() 返回标识特定测试用例的字符串。这通常是测试方法的全名,包括模块和类名
  • shortDescription() 返回测试的说明,如果未提供说明,则返回None。此方法的默认实现返回测试方法的docstring的第一行(如果可用),或者不返回
  • addCleanup(function, /, *args, kwargs) 添加要在tearDown()之后调用的函数,以清理测试期间使用的资源。函数的调用顺序与它们的添加顺序(后进先出)相反
  • doCleanups() 负责调用addCleanup()添加的所有清理函数。如果需要在tearDown()之前调用清理函数,则可以自己调用
  • doCleanups()如果setUp()引发异常,则在tearDown()之后或setUp()之后无条件调用此方法
  • addClassCleanup(function, /, *args, kwargs) 添加要在tearDownClass()之后调用的函数,以清理测试类期间使用的资源。函数的调用顺序与它们的添加顺序(后进先出)相反
    如果setUpClass()失败,意味着没有调用tearDownClass(),则添加的所有清理函数仍将被调用
  • doClassCleanups() 负责调用addClassCleanup()添加的所有清理函数。如果需要在tearDownClass()之前调用清理函数,则可以自己调用doClassCleanups()
  • unittest.IsolatedAsyncioTestCase(methodName=‘runTest’) 这个类提供了一个类似于TestCase的API,还接受协同路由作为测试函数
  • asyncSetUp() 准备测试夹具。这在setUp()之后调用。在调用测试方法之前立即调用它;除了AssertionError或SkipTest之外,
    此方法引发的任何异常都将被视为错误,而不是测试失败。默认实现不执行任何操作
  • asyncTearDown() 调用测试方法并记录结果后立即调用方法。这是在拆卸()之前调用的。即使测试方法引发异常,也会调用它,
    因此子类中的实现可能需要特别小心检查内部状态。此方法引发的任何异常(AssertionError或SkipTest除外)都将被视为附加错误,
    而不是测试失败(从而增加报告的错误总数)。无论测试方法的结果如何,仅当asyncSetUp()成功时才会调用此方法。默认实现不执行任何操作
  • addAsyncCleanup(function, /, *args, **kwargs) 此方法接受可用作清理函数的协同程序
  • run(result=None)

unittest.FunctionTestCase 允许测试运行程序驱动测试,但不提供测试代码可用于检查和报告错误的方法。这用于使用遗留测试代码创建测试用例,允许将其集成到基于unittest的测试框架中

四、unittest.mock 模拟对象库

简介:unittest.mock是一个用于测试的python库,允许使用模拟对象来替换受测系统的一些部分,并对这些部分如何被使用进行断言判断,从而使得单元测试将焦点只放在当前的单元功能。
提供的Mock类,能在整个测试套件中模拟大量的方法。创建后可以断言调用了哪些方法/属性及其参数。还可以以常规方式指定返回值并设置所需的属性
应用:1、开发人员某些接口还没有开发完毕
2、与第三方联调时,第三方拖了后腿,没准备好环境、数据都有可能。比如说我们测试的某个接口本身没有问题,但它依赖的某个接口有些问题,这就影响我们的正常测试任务进度
3、测试环境恶劣,模拟出无法访问的资源:比如说,你需要调用一个“墙”外的资源来方便自己调试,就可以自己Mock一个
4、开发只提供接口,数据自己搞
eg:

function.py

def add_and_multiply(x,y):
        addition = x + y
        multiple = multiply(x,y)
        return addition,multiple

     def multiply(x,y):
        return x * y

func_test.py

class MyTestCase(unittest.TestCase):
        # 正常用例
        def test_add_and_multiply(self):
            x = 3
            y = 5
            addition,multiple = function.add_and_multiply(x,y)
            self.assertEqual(8,addition)
            self.assertEqual(15,multiple)

        # multiply函数不可用时
        # @MOCK.patch.object(类名,"类中函数名")装饰/上下文管理区,模拟类或对象在模块测试,在测试过程中,指定的对象将被替换成为一个模拟,并在测试结束时还原
        # @mock.patch("模块名.
        函数名")
        @patch("test_mock.function.multiply")
        def test_add_and_multiply2(self,mock_multiply):
            x = 3
            y = 5
            # 设定mock_multiply的返回值固定为15
            mock_multiply.return_value = 15
            addition,multiply = function.add_and_multiply(x,y)
            # 校验mock_multiply方法的参数是否正确
            mock_multiply.assert_called_once_with(3,5)
            self.assertEqual(8,addition)
            self.assertEqual(15,multiply)

        # 执行真实函数
        def test_add_and_multiply3(self):
            x = 3
            y = 5
            # 若存在side_effect参数值,则该参数值覆盖return_value
            function.multiply = mock.Mock(return_value=1,side_effect=function.multiply)
            result = function.multiply(3,5)
            print(result)
            self.assertEqual(result,15)


if __name__ == "__main__":
    unittest.main()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值