unittest单元测试框架教程6-unittest.TestCase类详解

unittest.TestCase(methodName ='runTest' )

TestCase类的实例,作为编写的测试类的基类,具体测试由具体的子类(就是我们写的测试类)实现。此类实现测试运行程序所需的接口,以使其能够驱动测试,以及测试代码可用于检查和报告各种失败的方法。

每个TestCase实例(就是我们写的测试类)将运行一个基本方法:我们编写的测试方法。TestCase 实例提供了三组方法:一组用于运行测试,另一组由测试实现用于检查条件和报告故障,还有一些查询方法允许收集有关测试本身的信息。

第一组的方法是:

setUp()

 

在调用测试方法之前立即调用该方法。除了AssertionErrorSkipTest之外,此方法引发的任何异常都将被视为错误而不是测试失败。默认实现不执行任何操作。

 

tearDown()

调用测试方法并记录结果后立即调用的方法。即使测试方法引发了异常,也将调用此方法,因此子类中的实现可能需要特别注意检查内部状态。除了AssertionErrorSkipTest之外,此方法引发的任何异常都将被视为错误(errors)而不是测试失败(Failures)。setUp()无论测试方法的结果如何,仅在成功的情况下才调用此方法(wasSuccessful()==True)。默认实现不执行任何操作。

 

setUpClass()

 

在运行单个类中的测试之前调用的类方法。setUpClass以类作为唯一参数调用,并且必须修饰为classmethod()

@classmethod
def setUpClass(cls):
    ...

 

tearDownClass()

与setUpClass原理一致

 

run(result = None)

运行测试,将结果收集到TestResult作为result传递的对象中。如果省略resultNone,则创建一个临时结果对象(通过调用该defaultTestResult() 方法)并使用它。结果对象返回给run()的调用者。

通过简单地调用TestCase 实例。

result = TestAdd('test_add1').run()
result = TestAdd('test_chengfa').run()
print(result)

会生成一个测试结果

<unittest.result.TestResult run=1 errors=0 failures=1>

 

skipTest(reason)

@unittest.skip(reason)

跳过被此装饰器装饰的测试。 reason 为测试被跳过的原因。

@unittest.skipIf(conditionreason)

当 condition 为真时,跳过被装饰的测试。

@unittest.skipUnless(conditionreason)

跳过被装饰的测试,除非 condition 为真。

@unittest.expectedFailure

把测试标记为预计失败。如果测试不通过,会被认为测试成功;如果测试通过了,则被认为是测试失败。

exception unittest.SkipTest(reason)

引发此异常以跳过一个测试。

通常来说,你可以使用 TestCase.skipTest() 或其中一个跳过测试的装饰器实现跳过测试的功能,而不是直接引发此异常。

被跳过的测试的 setUp() 和 tearDown() 不会被运行。被跳过的类的 setUpClass() 和 tearDownClass() 不会被运行。被跳过的模组的 setUpModule() 和 tearDownModule() 不会被运行。

    def test_chengfa(self):
        '''测试乘法程序'''
        self.skipTest('暂不测试')
        ...

加入后运行,就会跳过

1
2
1
2
1
2
<unittest.runner.TextTestResult run=3 errors=0 failures=0>
.s.
----------------------------------------------------------------------
Ran 3 tests in 0.041s

OK (skipped=1)

 

subTest(msg = None** params)

此参数在***已经详细介绍,不重复介绍

 

debug()

 

运行测试而不收集结果。这样可以将测试引发的异常传播到调用方,并可以用于支持在调试器下运行测试。

result = TestAdd('test_add1').debug()
result = TestAdd('test_chengfa').debug()
print(result)

运行后会详细的输出错误信息,便于定位

1
2
Traceback (most recent call last):
  File "D:\PycharmProjects\untitled\testrunner.py", line 13, in <module>
    result = TestAdd('test_chengfa').debug()
  File "C:\Users\MZM\AppData\Local\Programs\Python\Python37-32\lib\unittest\case.py", line 681, in debug
    getattr(self, self._testMethodName)()
  File "D:\PycharmProjects\untitled\testmath.py", line 53, in test_chengfa
    self.assertEqual(resp['data'], self.a * self.b)
  File "C:\Users\MZM\AppData\Local\Programs\Python\Python37-32\lib\unittest\case.py", line 852, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\Users\MZM\AppData\Local\Programs\Python\Python37-32\lib\unittest\case.py", line 845, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: 3 != 2

第二组方法提供了一些断言方法来检查并报告故障。

unittest单元测试框架教程6-unittest.TestCase类详解

 

unittest单元测试框架教程6-unittest.TestCase类详解

 

assertRaises(exceptioncallable* args** kwds)

测试除法分母为0报异常

    def test_chufa(self):
        '''测试除法程序'''
        self.b = 0
        headers = {
            'Content-Type': "application/json",
        }
        reqdata = {'a':self.a,'b':self.b}
        resp = requests.request(method='POST', url='http://127.0.0.1:8000/testapi/chengfa/', verify=False, headers=headers, json=reqdata)
        resp = json.loads(resp.text)
        self.assertEqual(resp['status'],1)
        self.assertEqual(resp['message'], '请求成功')
        self.assertEqual(resp['data'], self.a / self.b)
1
0
<unittest.runner.TextTestResult run=1 errors=1 failures=0>
E
======================================================================
ERROR: test_chufa (testmath.TestAdd)
测试除法程序
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\PycharmProjects\untitled\testmath.py", line 67, in test_chufa
    self.assertEqual(resp['data'], self.a / self.b)
ZeroDivisionError: division by zero

----------------------------------------------------------------------
Ran 1 test in 0.029s

FAILED (errors=1)

加入assertraise断言后不会报错

        with self.assertRaises(ZeroDivisionError):
            self.assertEqual(resp['data'], self.a / self.b)
1
0
<unittest.runner.TextTestResult run=1 errors=0 failures=0>
.
----------------------------------------------------------------------
Ran 1 test in 0.030s

OK

 

assertRaisesRegex(exceptionregexcallable* args** kwds )

也是一样的操作

with self.assertRaisesRegex(ZeroDivisionError, 'ok'):
self.assertEqual(resp['data'], self.a / self.b)
F
======================================================================
FAIL: test_chufa (testmath.TestAdd)
测试除法程序
----------------------------------------------------------------------
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\PycharmProjects\untitled\testmath.py", line 68, in test_chufa
    self.assertEqual(resp['data'], self.a / self.b)
AssertionError: "ok" does not match "division by zero"

----------------------------------------------------------------------
Ran 1 test in 0.030s

FAILED (failures=1)
1
0
<unittest.runner.TextTestResult run=1 errors=0 failures=1>
with self.assertRaisesRegex(ZeroDivisionError, 'by'):
    self.assertEqual(resp['data'], self.a / self.b)
1
0
<unittest.runner.TextTestResult run=1 errors=0 failures=0>
.
----------------------------------------------------------------------
Ran 1 test in 0.028s

OK

 

用于执行更具体检查的方法

unittest单元测试框架教程6-unittest.TestCase类详解

 

 

 

 assertAlmostEqual(a, b)

举个例子self.assertAlmostEqual(1.00000002,1.00000001)第八位不报错,self.assertAlmostEqual(1.0000001,1.0000002)第七位就会报错,因为默认比的是第七位之前

self.assertAlmostEqual(1.02,1.01,1)不报错self.assertAlmostEqual(1.02,1.01,2)报错,因为默认比的是第二位之前

place参数表示第n位前都相等,之后无所谓

 

assertRegex(textregexmsg = None)

测试正则表达式搜索是否匹配(或不匹配)text

 

 

assertCountEqual(firstsecondmsg = None)

测试第一个序列是否包含与第二个相同的元素,而不管它们的顺序如何。否则,将生成一条错误消息,列出序列之间的差异。

 

下表总结了自动比较使用的特定类型方法的列表

unittest单元测试框架教程6-unittest.TestCase类详解

 

 

 

最后,TestCase提供以下方法和属性:

failmsg = None 

failureException

此类属性给出了测试方法引发的异常。如果测试框架需要使用专门的异常(可能带有其他信息),则它必须将该异常子类化,以便与框架“公平竞争”。此属性的初始值为 AssertionError

使用msgNone错误消息无条件地指示测试失败。

代码中加入

        if resp['status'] == 0:
            raise self.failureException(ConnectionError)

并修改测试程序使其返回status:0

1
2
<unittest.runner.TextTestResult run=1 errors=0 failures=1>
F
======================================================================
FAIL: test_add1 (testmath.TestAdd)
测试加法程序
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\PycharmProjects\untitled\testmath.py", line 26, in test_add1
    raise self.failureException(ConnectionError)
AssertionError: <class 'ConnectionError'>

----------------------------------------------------------------------
Ran 1 test in 0.035s

FAILED (failures=1)

 

测试框架可以使用以下方法来收集有关测试的信息:

countTestCases()

返回此测试对象表示的测试数量。

print(TestAdd('test_chengfa').countTestCases())
loader = unittest.TestLoader()
suite = loader.loadTestsFromTestCase(TestAdd)
print(suite.countTestCases())
suite.addTest(TestAdd('test_chengfa'))
print(suite.countTestCases())

1
4
5

 

id()

返回标识特定测试用例的字符串。这通常是测试方法的全名,包括模块和类名。

print(TestAdd('test_chengfa').id())

返回testmath.TestAdd.test_chengfa

 

shortDescription()

返回测试的描述,或者None没有提供描述。此方法的默认实现返回测试方法docstring的第一行(如果有),或None

 

doCleanups()

tearDown()或在setUp()引发异常之后无条件调用此方法。

如果使setup方法报错

def setUp(self):
self.file = open('testtext.txt','w+',encoding='utf-8')
self.file.write('测试开始')
self.a = 1/0
self.b = 2/0

def tearDown(self):
print(self.a)
print(self.b)
self.file.write('测试结束')
self.file.close()


...

runner = unittest.TextTestRunner()
suite = unittest.TestSuite()
suite.addTest(TestAdd('test_add1'))
result = runner.run(suite)

出现错误,且不会运行tearDown

E
======================================================================
ERROR: test_add1 (testmath.TestAdd)
测试加法程序
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\PycharmProjects\untitled\testmath.py", line 11, in setUp
    self.a = 1/0
ZeroDivisionError: division by zero

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)
<unittest.runner.TextTestResult run=1 errors=1 failures=0>

加入doCleanups()后

    def doCleanups(self):
        self.file.write('测试结束')
        self.file.close()

就会将"测试结束"写入文件了

 

 

 
上一篇:unittest测试框架学习和源码走读(4)


下一篇:第一次作业--开发环境配置介绍