一、介紹
在軟體開發中,單元測試是一種測試方法,它用於檢查單個軟體元件(例如函式或方法)的正確性。Python 提供了一個內建的單元測試庫,名為 unittest
,可以用來編寫測試程式碼,然後執行測試,並報告測試結果。
本文將向你介紹如何使用 unittest
來編寫和執行單元測試。透過閱讀本文,你將瞭解 unittest
的基本使用方法,以及如何使用 unittest
中的斷言方法和測試用例組織結構。
二、基礎概念和方法
在 unittest
中,每個測試用例都是 unittest.TestCase
的一個例項,而測試用例的集合就是一個測試套件。你可以透過實現 unittest.TestCase
的子類來定義你的測試用例,然後透過例項化這個子類的物件來建立具體的測試用例。
這是一個簡單的示例,演示瞭如何定義和使用測試用例:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
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()
在上述程式碼中,我們定義了一個 TestStringMethods
類,這個類繼承自 unittest.TestCase
。在這個類中,我們定義了三個方法:test_upper
、test_isupper
和 test_split
。這三個方法就是我們的三個測試用例。
unittest.TestCase
類提供了許多斷言方法,例如 assertEqual(a, b)
、assertTrue(x)
和 assertFalse(x)
。這些斷言方法用來檢查我們的程式碼是否滿足預期的行為。
三、執行測試和檢視測試結果
當我們定義好測試用例後,就可以執行這些測試用例,並檢視測試結果了。你可以透過執行 unittest.main()
來執行所有的測試用例。
在上述程式碼的最後,我們呼叫了 unittest.main()
。這個函式會搜尋當前模組中所有 unittest.TestCase
的子類,然後執行這些子類中的所有以 test
開頭的方法。
當我們執行這段程式碼時,unittest
將會輸出一個測試報告,顯示每個測試用例的執行結果。例如,如果所有測試用例都透過了,你會看到如下的輸出:
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
四、使用測試載入器和測試執行器
測試載入器用於搜尋和載入測試,而測試執行器則負責執行這些測試並報告結果。Python的unittest庫為我們提供了預設的測試載入器和測試執行器,但是,你也可以自定義它們以滿足特殊的需求。
下面是一個示例,演示瞭如何使用 unittest.TestLoader
來載入測試:
import unittest
class TestStringMethods(unittest.TestCase):
# ... 前面的內容 ...
def suite():
suite = unittest.TestSuite()
loader = unittest.TestLoader()
suite.addTest(loader.loadTestsFromTestCase(TestStringMethods))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite())
在這個例子中,我們首先建立了一個 unittest.TestLoader
例項。然後,我們呼叫了 loadTestsFromTestCase
方法,這個方法會載入 TestStringMethods
類中定義的所有測試。然後,我們將這些測試新增到了測試套件中。
至於測試執行器,unittest
提供了 unittest.TextTestRunner
類作為預設的測試執行器。這個類的例項會在控制檯上輸出一個文字報告。如果你想自定義測試執行器,你可以透過繼承 unittest.TestRunner
類來實現。
五、測試套件
測試套件是測試用例或測試套件的集合。它用於指定 unittest
所需執行的測試。透過建立自己的測試套件,你可以精確控制 unittest
執行哪些測試。以下是一個建立測試套件並新增測試用例的例子:
import unittest
class TestStringMethods(unittest.TestCase):
# ... 與前文相同 ...
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())
在這個例子中,我們建立了一個 suite
函式,這個函式建立一個 unittest.TestSuite
例項,然後向這個例項新增測試用例。在 main
部分,我們建立了一個 unittest.TextTestRunner
例項,然後呼叫它的 run
方法來執行測試套件。
六、setUp 和 tearDown 方法
除了用於測試的方法外,unittest.TestCase
還提供了兩個特殊的方法:setUp
和 tearDown
。這兩個方法在每個測試方法之前和之後執行,可以用於準備測試環境和清理資源。
下面是一個使用 setUp
和 tearDown
的例子:
import unittest
class TestDatabaseMethods(unittest.TestCase):
def setUp(self):
self.conn = create_database_connection()
self.cur = self.conn.cursor()
def tearDown(self):
self.cur.close()
self.conn.close()
def test_insert(self):
self.cur.execute("INSERT INTO employees VALUES (1, 'John')")
self.cur.execute("SELECT * FROM employees")
result = self.cur.fetchone()
self.assertEqual(result, (1, 'John'))
if __name__ == '__main__':
unittest.main()
在這個例子中,我們在 setUp
方法中建立了資料庫連線和遊標,在 tearDown
方法中關閉了它們。這樣,我們就可以確保每個測試方法都在乾淨的資料庫環境中執行。
七、unittest.mock:模擬物件和行為
在某些情況下,你可能想要替換測試中的一些物件,或者模擬特定的行為。unittest.mock
模組提供了一個 Mock
類和許多其他工具,可以幫助你實現這一點。
下面是一個使用 unittest.mock
的例子:
from unittest import TestCase, mock
from my_module import MyObject
class TestMyObject(TestCase):
@mock.patch('my_module.MyObject')
def test_my_method(self, MockMyObject):
obj = MockMyObject()
obj.my_method.return_value = 42
assert obj.my_method() == 42
obj.my_method.assert_called_once()
在這個例子中,我們使用了 unittest.mock.patch
裝飾器來替換 MyObject
類。然後,我們可以控制這個替代物件的行為,例如設定它的方法返回什麼值,或者檢查它的方法是否被正確呼叫。
總的來說,Python的 unittest
框架為我們提供了強大而靈活的工具來進行單元測試。這只是 unittest
的冰山一角,它還有更多的功能等待你去發現和利用。