unittest框架系列二(程式碼編寫與用例組織)
程式碼編寫與用例組織
歡迎加入測試交流群:夜行者自動化測試(816489363)進行交流學習QAQ
–成都-阿木木
再使用unittest
編寫你的測試程式碼時,測試類必須繼承TestCase
或者FunctionTestCase
.
官網有一段組織測試用例的描述,為什麼會衍生出setup/teardown/setUpClass/tearDownClass
,用比較直白的話來表述,就是我們不會在每一個test method中去例項化測試物件等公共操作,這些重複的操作會導致程式碼看起來很難看,所以提供了夾具test fixture來進行設定這一類需要在每個測試類或者測試方法前後進行環境初始化,或者環境清理的物件或公共操作。
當用例執行發現setup/setUpClass
方法執行失敗時,不會再執行後面的test method
,當teardown/tearDownClass
執行失敗時,test_method
方法仍然會執行。
一條測試用例是如何標記為失敗呢?使用基類assert*()
提供的方法對於用例中的結果進行斷言,如果斷言失敗,就會引發異常。也就是說unittest
框架通過識別異常將用例標記為fail。其他不屬於assert
丟擲的異常,都會被識別成ERROR。
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/28 11:32
@Auth : chineseluo
@Email : [email protected]
@File : unittest_demo.py
@IDE : PyCharm
------------------------------------
"""
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("運行於測試方法前,主要用於環境初始化")
def tearDown(self):
print("運行於測試方法後,主要使用者環境資料清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
print("this is a test_isupper method")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
執行結果:
運行於測試方法前,主要用於環境初始化
this is a test_isupper method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
this is a test_split method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
this is a test_upper method
運行於測試方法後,主要使用者環境資料清理
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
在下面的例子中修改test_upper方法中的self.assertEqual('foo'.upper(), 'FOO')
為self.assertEqual('foo'.upper(), 'FO')
,檢視斷言異常執行結果,可以看到FAILED(failures=1)
,屬於unittest
可識別的斷言異常。
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("運行於測試方法前,主要用於環境初始化")
def tearDown(self):
print("運行於測試方法後,主要使用者環境資料清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FO')
def test_isupper(self):
print("this is a test_isupper method")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
執行結果為:
C:\Users\luozhongwen\AppData\Local\Programs\Python\Python38\python.exe D:/TestScriptDir/python_web/mysite/unittest_demo.py
..F
======================================================================
FAIL: test_upper (__main__.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:/TestScriptDir/python_web/mysite/unittest_demo.py", line 26, in test_upper
self.assertEqual('foo'.upper(), 'FO')
AssertionError: 'FOO' != 'FO'
- FOO
? -
+ FO
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1)
運行於測試方法前,主要用於環境初始化
this is a test_isupper method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
this is a test_split method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
this is a test_upper method
運行於測試方法後,主要使用者環境資料清理
Process finished with exit code 1
在下面的例子的test_isupper
中新增一個非斷言異常,索引越界異常,檢視執行結果,可以看到這是一個非assert的異常,被標記為了error
。
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("運行於測試方法前,主要用於環境初始化")
def tearDown(self):
print("運行於測試方法後,主要使用者環境資料清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
print("this is a test_isupper method")
a = [1, 2, 3]
print(a[4])
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
結果為:
======================================================================
ERROR: test_isupper (__main__.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:/TestScriptDir/python_web/mysite/unittest_demo.py", line 31, in test_isupper
print(a[4])
IndexError: list index out of range
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (errors=1)
運行於測試方法前,主要用於環境初始化
this is a test_isupper method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
this is a test_split method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
this is a test_upper method
運行於測試方法後,主要使用者環境資料清理
Process finished with exit code 1
執行用例:
unittest
框架建議在進行測試用例編寫時,按照功能進行測試用例分組,unittest
提供了一種機制:測試套件,由unittest
的TestSuite
類表示。通常使用unittest.main()
,它會自動收集所有模組的測試用例並執行它們。
有時候我們需要自定義測試套件的構建,需要自己進行測試套的新增。
- 測試套可以放在相同的模組(例如:
unittest_demo.py
),針對當前測試模組,測試用例,測試方法 - 測試套也可以放在一個指令碼的入口模組中,例如
run.py
中,進行各個測試模組中細分的方法的執行
放在相同指令碼的當中:
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/28 11:32
@Auth : chineseluo
@Email : [email protected]
@File : unittest_demo.py
@IDE : PyCharm
------------------------------------
"""
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("運行於測試方法前,主要用於環境初始化")
def tearDown(self):
print("運行於測試方法後,主要使用者環境資料清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
def suite():
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
執行結果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
運行於測試方法前,主要用於環境初始化
this is a test_upper method
運行於測試方法後,主要使用者環境資料清理
運行於測試方法前,主要用於環境初始化
運行於測試方法後,主要使用者環境資料清理
Process finished with exit code 0
放在不同的指令碼中,通過匯入需要進行自定義測試套件的模組下的測試類:
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/28 11:32
@Auth : chineseluo
@Email : [email protected]
@File : unittest_demo.py
@IDE : PyCharm
------------------------------------
"""
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self):
print("運行於測試方法前,主要用於環境初始化")
def tearDown(self):
print("運行於測試方法後,主要使用者環境資料清理")
def test_upper(self):
print("this is a test_upper method")
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
print("this is a test_split method")
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
run.py
#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
------------------------------------
@Project : mysite
@Time : 2020/8/31 9:29
@Auth : chineseluo
@Email : [email protected]
@File : run.py
@IDE : PyCharm
------------------------------------
"""
import unittest
from unittest_demo import TestStringMethods
def suite():
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())