一、介紹
- unittest模塊是python進(jìn)行單元測(cè)試的框架;
- unittest的概念:
- test case:測(cè)試用例;
- test fixture:測(cè)試固定裝置(常用的為:用例執(zhí)行前的操作setUp()和用例執(zhí)行后的操作tearDown());
- test suite:測(cè)試套件,即測(cè)試用例的集合,可通過(guò)addTest()的方法添加TestCase或通過(guò)TestLoader自動(dòng)添加TestCase;
- test runner:測(cè)試執(zhí)行器,可執(zhí)行測(cè)試套件,也可執(zhí)行測(cè)試用例;
測(cè)試執(zhí)行最簡(jiǎn)單的方法是使用unittest.main(),它會(huì)搜索所有以test開(kāi)頭的測(cè)試用例,按ASCII的順序依次執(zhí)行;
使用test runner的方法執(zhí)行執(zhí)行,它可通過(guò)TextTestRunner()方法初始化一個(gè)測(cè)試執(zhí)行器,再使用run()函數(shù)執(zhí)行測(cè)試套件;
- 使用方法
- 導(dǎo)入unittest模塊:import unittest
- 定義一個(gè)測(cè)試類(lèi),繼承unittest.TestCase:class ClassName(unittest.TestCase)
- 測(cè)試類(lèi)中每個(gè)測(cè)試用例的函數(shù),函數(shù)名必須要test開(kāi)頭(若函數(shù)沒(méi)有以test開(kāi)頭,則不會(huì)執(zhí)行該條用例)
- 使用unittest.TestCase自帶的斷言函數(shù)assert*判斷測(cè)試結(jié)果是否相同
- 運(yùn)行主函數(shù)
unittest常用工作流程:
TestLoader將測(cè)試用例TestCase添加到TestSuite中,TextTestRunner調(diào)用TestSuite的run方法,按測(cè)試用例的函數(shù)名ASCII的排列順序依次執(zhí)行用例,最后獲得測(cè)試結(jié)果TestResult。
執(zhí)行TestCase的過(guò)程:先執(zhí)行setUp()方法,若執(zhí)行成功,則繼續(xù)執(zhí)行測(cè)試用例函數(shù),無(wú)論測(cè)試用例是否執(zhí)行成功均會(huì)執(zhí)行tearDown()方法;若setUp()方法執(zhí)行失敗,則整個(gè)測(cè)試項(xiàng)目執(zhí)行失?。?/p>斷言的使用
使用assert*方法來(lái)檢查測(cè)試結(jié)果,若assert檢查失敗,則拋出異常,unittest將其作為一個(gè)失敗用例(即類(lèi)型為failure); 非assert導(dǎo)致的異常,unittest會(huì)將其作為一個(gè)錯(cuò)誤(即類(lèi)型為error)。
failure一般表示實(shí)際結(jié)果與預(yù)期結(jié)果不一致,表示測(cè)試用例執(zhí)行失敗;
error一般表示測(cè)試代碼有bug;
二、setUp、tearDown與setUpClass、tearDownClass操作
- setUp與tearDown操作:
- def setUp(self):每個(gè)測(cè)試用例執(zhí)行之前,使用setUP函數(shù)進(jìn)行初始化,相當(dāng)于用例執(zhí)行前的準(zhǔn)備工作;
若setUp函數(shù)中出現(xiàn)任何異常,則會(huì)終止當(dāng)前測(cè)試用例;
除unittest.SkipTest和AssertionError異常外,所有的異常類(lèi)型均為ERROR;否則為FAIL; - def tearDown(self):每個(gè)測(cè)試用例執(zhí)行后,使用tearDown函數(shù)進(jìn)行退出操作,相當(dāng)于用例執(zhí)行后的清除工作;
無(wú)論測(cè)試用例是否執(zhí)行成功,均會(huì)執(zhí)行tearDown()方法;
若tearDown函數(shù)中出現(xiàn)任何異常,除unittest.SkipTest和AssertionError異常外,所有的異常類(lèi)型均為ERROR;否則為FAIL;
- setUpClass與tearDownClass操作:
- def setUpClass(cls):所有用例執(zhí)行前,整個(gè)類(lèi)開(kāi)始執(zhí)行的函數(shù),必須使用裝飾器@classmethod;
- def tearDownClass(cls):所有用例執(zhí)行結(jié)束后,整個(gè)類(lèi)結(jié)束執(zhí)行的函數(shù),必須使用裝飾器@classmethod;
class Sample1(unittest.TestCase):
def setUp(self):
print("start")
def tearDown(self):
print("end")
def testAdd(self):
self.assertEqual(2 + 3, 5)
def testReduce(self):
self.assertEqual(7 - 5, 2)
if __name__ == '__main__':
unittest.main()
"""結(jié)果
..
start
end
start
end
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
"""
class Sample2(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("start")
@classmethod
def tearDownClass(cls):
print("end")
def testAdd(self):
self.assertEqual(2 + 3, 5)
def testReduce(self):
self.assertEqual(7 - 5, 2)
if __name__ == '__main__':
unittest.main()
"""結(jié)果
..
start
end
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
"""
三、斷言函數(shù)介紹
unittest.TestCase自帶的有多種斷言函數(shù)的方法,可用來(lái)判斷自動(dòng)化測(cè)試的結(jié)果是否正確。
- assertEqual(first, second, msg=None):判斷first == second;
若相等,則執(zhí)行成功;若不等,則執(zhí)行FAIL,同時(shí)輸出錯(cuò)誤信息msg; - assertNotEqual(first, second, msg=None):判斷first != second;
- assertAlmostEqual(first, second, places=None, msg=None,delta=None):判斷first與second是否約等于,places為小數(shù)點(diǎn)后精確的位數(shù),delta為比較兩個(gè)變量的差值的絕對(duì)值是否在delta范圍內(nèi)(places與delta不可同時(shí)存在);
- assertNotAlmostEqual(first, second, places=None, msg=None,delta=None):判斷first與second是否不約等于;
- assertIs(expr1, expr2, msg=None):判斷expr1 is expr2;
- assertIsNot(expr1, expr2, msg=None):判斷expr1 is not expr2;
- assertIsNone(obj, msg=None):判斷obj is None;
- assertIsNotNone(obj, msg=None):判斷obj is not None;
- assertIn(member, container, msg=None):判斷member in container;
- assertNotIn(member, container, msg=None):判斷member not in container;
- assertIsInstance(obj, cls, msg=None):判斷obj是cls實(shí)例, isinstance(obj, cls);
- assertNotIsInstance(obj, cls, msg=None):判斷obj不是cls的實(shí)例, not isinstance(obj, cls);
obj和cls必須是一個(gè)類(lèi)型或一個(gè)類(lèi)型元組 - assertGreater(a, b, msg=None):判斷a > b;
- assertGreaterEqual(a, b, msg=None):判斷a >= b;
- assertLess(a, b, msg=None):判斷a < b;
- assertLessEqual(a, b, msg=None):判斷a <= b;
- assertTrue(expr, msg=None):判斷bool(expr)為T(mén)rue;
- assertFalse(expr, msg=None):判斷bool(expr)為False;
- assertRaises(expected_exception, *args, **kwargs):驗(yàn)證程序應(yīng)拋出的異常信息
import unittest
class Assertion(unittest.TestCase):
"""斷言函數(shù)的使用"""
def setUp(self):
self.driver = "0123456789ABC"
def test_01(self):
"""測(cè)試用例"""
# 判斷兩值是否相等
self.assertEqual("0123456789ABC", self.driver, msg="設(shè)備相同")
# 判斷兩值是否約等于
self.assertAlmostEqual(3.141, 3.145, places=2)
self.assertAlmostEqual(3.15, 3.17, delta=0.03)
def tearDown(self):
pass
if __name__ == '__main__':
unittest.main()
四、忽略測(cè)試用例操作
可通過(guò)unittest.skip裝飾器跳過(guò)測(cè)試用例或測(cè)試類(lèi)
- @unittest.skip(reason):無(wú)條件中跳過(guò)測(cè)試用例或測(cè)試類(lèi),reason為跳過(guò)此測(cè)試的原因;
- @unittest.skipIf(condition, reason):當(dāng)測(cè)試條件condintion為true時(shí)跳過(guò)測(cè)試用例或測(cè)試類(lèi),reason為跳過(guò)此測(cè)試的原因;
- @unittest.skipUnless(condition, reason):當(dāng)測(cè)試條件condintion為false時(shí)跳過(guò)測(cè)試用例或測(cè)試類(lèi),reason為跳過(guò)此測(cè)試的原因;
- @unittest.expectedFailure:表示當(dāng)測(cè)試失敗時(shí),這條測(cè)試不計(jì)入失敗的case數(shù)目,而是計(jì)入expected_failure中;
import unittest
test_version = (0, 1, 2, 3)
class SkipTestCase(unittest.TestCase):
"""忽略測(cè)試用例方法"""
@classmethod
def setUpClass(cls):
print("start")
@classmethod
def tearDownClass(cls):
print("end")
def test_01(self):
print("test1")
@unittest.skip('skipping when demo is running')
def test_02(self):
"""程序運(yùn)行時(shí)無(wú)條件跳過(guò)此條用例"""
print("test2")
@unittest.skipIf(test_version < (5,), "test condition don't support")
def test_03(self):
"""test_version滿(mǎn)足小于5時(shí),跳過(guò)此用例"""
print("test3")
@unittest.skipUnless(test_version > (5,), "test condition don't support")
def test_04(self):
"""test_version不滿(mǎn)足大于5時(shí),跳過(guò)此用例"""
print("test4")
@unittest.expectedFailure
def test_05(self):
print(1 > 2)
@unittest.skip("skip this test class")
class SkipTestClass(unittest.TestCase):
"""忽略測(cè)試類(lèi)"""
@classmethod
def setUpClass(cls):
print("start")
@classmethod
def tearDownClass(cls):
print("end")
def test_07(self):
print("test7")
if __name__ == '__main__':
unittest.main()
五、unittest.main()介紹
用于將一個(gè)單元測(cè)試模塊變?yōu)榭芍苯舆\(yùn)行的測(cè)試腳本,main()方法使用TestLoader來(lái)搜索所有包含在此模塊下的以test命名開(kāi)頭的測(cè)試方法,并依次執(zhí)行用例;
執(zhí)行用例的默認(rèn)順序是按ASCII碼的順序加載測(cè)試用例(即0-9,A-Z,a-z)
---此為最簡(jiǎn)單的執(zhí)行unittest用例的方法,但若需按自己的順序執(zhí)行用例或添加保存測(cè)試報(bào)告可通過(guò)測(cè)試套件的方法,見(jiàn)如下。