Python+Unittest+自動化:使用Python進行單元測試
unittest單元測試框架不僅可以適用於單元測試,還可以將其用於自動化測試用例的開發與執行,該測試框架可組織執行測試用例,並且提供了豐富的斷言方法,判斷測試用例是否通過,最終生成測試結果。
1.Unitest單元測試
對於單元測試,需要設定預先條件,對比預期結果和實際結果。
unittest庫提供了testSuite、testCase、testRunner、Skip等,具體有以下作用:
1.1 testSuite 測試套件
testSuite = unittest.TestSuite() testSuite.addTest()
1.2 testCase 測試用例
測試用例是一個完整的測試流程,包括測試前準備環境的搭建(setUp),執行測試程式碼(run),測試後環境的還原(tearDown),以及判斷測試得到的實際結果和預期結果是否相等決定的的assert*():
assertEqual(a,b,[msg='測試失敗時列印的資訊']):斷言a和b是否相等,相等則測試用例通過。
assertNotEqual(a,b,[msg='測試失敗時列印的資訊']):斷言a和b是否相等,不相等則測試用例通過。
assertTrue(x,[msg='測試失敗時列印的資訊']):斷言x是否True,是True則測試用例通過。
assertFalse(x,[msg='測試失敗時列印的資訊']):斷言x是否False,是False則測試用例通過。
assertIs(a,b,[msg='測試失敗時列印的資訊']):斷言a是否是b,是則測試用例通過。
assertNotIs(a,b,[msg='測試失敗時列印的資訊']):斷言a是否是b,不是則測試用例通過。
assertIsNone(x,[msg='測試失敗時列印的資訊']):斷言x是否None,是None則測試用例通過。
assertIsNotNone(x,[msg='測試失敗時列印的資訊']):斷言x是否None,不是None則測試用例通過。
assertIn(a,b,[msg='測試失敗時列印的資訊']):斷言a是否在b中,在b中則測試用例通過。
assertNotIn(a,b,[msg='測試失敗時列印的資訊']):斷言a是否在b中,不在b中則測試用例通過。
assertIsInstance(a,b,[msg='測試失敗時列印的資訊']):斷言a是是b的一個例項,是則測試用例通過。
assertNotIsInstance(a,b,[msg='測試失敗時列印的資訊']):斷言a是是b的一個例項,不是則測試用例通過。
class Test(unittest.TestCase): @classmethod def setUpClass(cls): print('測試開始啦...') @classmethod def tearDownClass(cls): print('測試結束啦...') def setUp(self): print('setUp...') def tearDown(self): print('setDown...') def test_testcase(self): self.assertEqual(1, 0)
1.3 testRunner 執行測試並輸出結果
直接執行測試用例,按照命名順序執行。 unittest.main()
執行測試並在控制檯輸出測試結果:
unittest.TextTestRunner(verbosity=2).run(testSuite)
fileName = 'Report/Milito_Test'+str(time.time()).replace('.','')+'.html' f = open(fileName, 'wb') runner = HTMLTestReportCN.HTMLTestRunner(stream=f, title='測試報告', description='測試報告') runner.run(testSuite) f.close()
1.4 Skip 裝飾器
當執行用例時,有些用例如果不想執行,可用裝飾器暫時遮蔽該條測試用例。一種常見的用法就是比如說想除錯某一個測試用例,想先遮蔽其他用例就可以用裝飾器遮蔽。
@unittest.skip(reason): skip(reason)裝飾器:無條件跳過裝飾的測試,並說明跳過測試的原因。
@unittest.skipIf(reason): skipIf(condition,reason)裝飾器:條件為真時,跳過裝飾的測試,並說明跳過測試的原因。
@unittest.skipUnless(reason): skipUnless(condition,reason)裝飾器:條件為假時,跳過裝飾的測試,並說明跳過測試的原因。
@unittest.expectedFailure(): expectedFailure()測試標記為失敗。
2.將unitTest用於自動化測試
python可以編寫Web頁面和APP自動化測試指令碼[之前的文章],對於編寫的自動化測試指令碼進行以下操作,即可將unitTest用於自動化測試。
2.1 將自動化測試指令碼劃分為合適的用例,放在testCase之中。
2.2 每一個自動化測試指令碼的用例執行完之後,新增斷言,判斷測試是否成功。
2.3 每一個自動化測試指令碼本身可能存在一些問題,用try: *** except Exception as e: *** 丟擲異常,並在except中新增失敗的斷言。
2.4 如果自動化測試用例是否執行需要遵照某種規律,則設定變數進行標記,使用skip裝飾器對變數進行判斷,以跳過不執行的用例。
2.5 如果unitTest需要傳引數,則呼叫UnittestWithParam,並對unitTest+自動化測試 指令碼進行以下修改。
# -*- coding:utf-8 -*-
# UnittestWithParam.py
import unittest
class ParametrizedTestCase(unittest.TestCase):
""" TestCase classes that want to be parametrized should
inherit from this class.
"""
def __init__(self, methodName='runTest', param=None):
super(ParametrizedTestCase, self).__init__(methodName)
self.param = param
@staticmethod
def parametrize(testcase_klass, param=None):
""" Create a suite containing all tests taken from the given
subclass, passing them the parameter 'param'.
"""
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(testcase_klass)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(testcase_klass(name, param=param))
return suite
# -*- coding:utf-8 -*-
import unittest
import HTMLTestReportCN
##用法-testcase
class TestOne(ParametrizedTestCase):
def setUp(self):
self.num = 9
print("開始")
def tearDown(self):
print("完成")
def test_something(self):
self.assertEqual(self.param, self.num)
def test_something_else(self):
self.assertEqual(self.param, self.num)
##用法-測試
def main():
suite = unittest.TestSuite()
suite.addTest(ParametrizedTestCase.parametrize(TestOne, param=None))
suite.addTest(ParametrizedTestCase.parametrize(TestOne, param=13))
# 控制檯輸出結果
unittest.TextTestRunner(verbosity=2).run(suite)
# 生成測試報告
"""
fileName = 'unitTestParam.html'
f = open(fileName, 'wb')
runner = HTMLTestReportCN.HTMLTestRunner(stream=f, title='UT', description='測試報告')
runner.run(suite)
f.close()
"""
if __name__=="__main__":
main()
3.總結
使用python+unitTest進行自動化測試,是對自動化測試指令碼進行更深度思考的機會,可以讓測試指令碼更接近高內聚低耦合的狀態,提升測試人員的工作效率。