unittest單元測試框架教程6-unittest.TestCase類詳解
unittest.
TestCase(methodName ='runTest')
TestCase
類的例項,作為編寫的測試類的基類,具體測試由具體的子類(就是我們寫的測試類)實現。此類實現測試執行程式所需的介面,以使其能夠驅動測試,以及測試程式碼可用於檢查和報告各種失敗的方法。
每個TestCase
例項(就是我們寫的測試類)將執行一個基本方法:我們編寫的測試方法。TestCase
例項提供了三組方法:一組用於執行測試,另一組由測試實現用於檢查條件和報告故障,還有一些查詢方法允許收集有關測試本身的資訊。
第一組的方法是:
setUp
()
在呼叫測試方法之前立即呼叫該方法。除了AssertionError
或SkipTest
之外,此方法引發的任何異常都將被視為錯誤而不是測試失敗。預設實現不執行任何操作。
tearDown
()
呼叫測試方法並記錄結果後立即呼叫的方法。即使測試方法引發了異常,也將呼叫此方法,因此子類中的實現可能需要特別注意檢查內部狀態。除了AssertionError
或SkipTest
之外,此方法引發的任何異常都將被視為錯誤(errors)而不是測試失敗(Failures)。setUp()
無論測試方法的結果如何,僅在成功的情況下才呼叫此方法(wasSuccessful()==True)。預設實現不執行任何操作。
setUpClass
()
在執行單個類中的測試之前呼叫的類方法。setUpClass
以類作為唯一引數呼叫,並且必須修飾為classmethod()
:
@classmethod def setUpClass(cls): ...
tearDownClass
()
與setUpClass原理一致
run
(result = None)
執行測試,將結果收集到TestResult
作為result傳遞的物件中。如果省略result或None
,則建立一個臨時結果物件(通過呼叫該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
(condition,reason)-
當condition為真時,跳過被裝飾的測試。
@
unittest.
skipUnless
(condition,reason)-
跳過被裝飾的測試,除非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
第二組方法提供了一些斷言方法來檢查並報告故障。
assertRaises
(exception,callable,* 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(
exception,regex,callable,* 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
用於執行更具體檢查的方法
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
(text,regex,msg = None)
測試正則表示式搜尋是否匹配(或不匹配)text。
assertCountEqual
(first,second,msg = None)
測試第一個序列是否包含與第二個相同的元素,而不管它們的順序如何。否則,將生成一條錯誤訊息,列出序列之間的差異。
下表總結了自動比較使用的特定型別方法的列表
最後,TestCase
提供以下方法和屬性:
fail
(msg = None)
failureException
此類屬性給出了測試方法引發的異常。如果測試框架需要使用專門的異常(可能帶有其他資訊),則它必須將該異常子類化,以便與框架“公平競爭”。此屬性的初始值為AssertionError
。
使用msg或None
錯誤訊息無條件地指示測試失敗。
程式碼中加入
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()
就會將"測試結束"寫入檔案了