鍍金池/ 教程/ Python/ 單元測試
基礎
itertools
HTTP 服務
hashlib
閉包
文件和目錄
單元測試
使用 @property
標準模塊
陌生的 metaclass
Base64
進程、線程和協(xié)程
讀寫二進制文件
匿名函數(shù)
輸入和輸出
Click
元組
字符編碼
partial 函數(shù)
參考資料
collections
協(xié)程
類和實例
Python 之旅
定制類和魔法方法
常用數(shù)據(jù)類型
繼承和多態(tài)
ThreadLocal
HTTP 協(xié)議簡介
Requests 庫的使用
讀寫文本文件
列表
os 模塊
迭代器 (Iterator)
正則表達式
集合
上下文管理器
異常處理
你不知道的 super
定義函數(shù)
datetime
資源推薦
字典
slots 魔法
hmac
第三方模塊
進程
類方法和靜態(tài)方法
函數(shù)參數(shù)
高階函數(shù)
函數(shù)
re 模塊
高級特性
線程
argparse
生成器
結束語
字符串
map/reduce/filter
函數(shù)式編程
Celery
裝飾器

單元測試

軟件系統(tǒng)的開發(fā)是一個很復雜的過程,隨著系統(tǒng)復雜性的提高,代碼中隱藏的 bug 也可能變得越來越多。為了保證軟件的質量,測試是一個必不可少的部分,甚至還有測試驅動開發(fā)(Test-driven development, TDD)的理念,也就是先測試再編碼。

在計算機編程中,單元測試(Unit Testing)又稱為模塊測試,是針對程序模塊(軟件設計的最小單位)來進行正確性檢驗的測試工作,所謂的單元是指一個函數(shù),一個模塊,一個類等。

在 Python 中,我們可以使用 unittest 模塊編寫單元測試。

下面以官方文檔的例子進行介紹,該例子對字符串的一些方法進行測試:

# -*- coding: utf-8 -*-

import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')    # 判斷兩個值是否相等

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())          # 判斷值是否為 True
        self.assertFalse('Foo'.isupper())         # 判斷值是否為 False

    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)

在上面,我們定義了一個 TestStringMethods 類,它從 unittest.TestCase 繼承。注意到,我們的方法名都是以 test 開頭,表明該方法是測試方法,不以 test 開頭的方法測試的時候不會被執(zhí)行。

在方法里面,我們使用了斷言(assert)判斷程序運行的結果是否和預期相符。其中:

  • assertEqual 用于判斷兩個值是否相等;
  • assertTrue/assertFalse 用于判斷表達式的值是 True 還是 False;
  • assertRaises 用于檢測異常;

斷言方法主要有三種類型:

  • 檢測兩個值的大小關系:相等,大于,小于等
  • 檢查邏輯表達式的值:True/Flase
  • 檢查異常

下面列舉了部分常用的斷言方法:

Method Checks that
assertEqual(a, b) a == b
assertNotEqual(a, b) a != b
assertGreater(a, b) a > b
assertGreaterEqual(a, b) a >= b
assertLess(a, b) a < b
assertLessEqual(a, b) a <= b
assertTrue(x) bool(x) is True
assertFalse(x) bool(x) is False
assertIs(a, b) a is b
assertIsNot(a, b) a is not b
assertIsNone(x) x is None
assertIsNotNone(x) x is not None
assertIn(a, b) a in b
assertNotIn(a, b) a not in b
assertIsInstance(a, b) isinstance(a, b)
assertNotIsInstance(a, b) not isinstance(a, b)

現(xiàn)在,讓我們來運行上面的單元測試,將上面的代碼保存為文件 mytest.py,通過 -m unittest 參數(shù)運行單元測試:

$ python -m unittest mytest
test_isupper (mytest.TestStringMethods) ... ok
test_split (mytest.TestStringMethods) ... ok
test_upper (mytest.TestStringMethods) ... ok

執(zhí)行結果:

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

上面的結果表明測試通過,我們也可以加 -v 參數(shù)得到更加詳細的測試結果:

$ python -m unittest -v mytest
test_isupper (mytest.TestStringMethods) ... ok
test_split (mytest.TestStringMethods) ... ok
test_upper (mytest.TestStringMethods) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

上面這種運行單元測試的方法是我們推薦的做法,當然,你也可以在代碼的最后添加兩行:

if __name__ == '__main__':
    unittest.main()

然后再直接運行:

$ python mytest.py

setUp 和 tearDown

在某些情況下,我們需要在每個測試方法執(zhí)行前和執(zhí)行后做一些相同的操作,比如我們想在每個測試方法執(zhí)行前連接數(shù)據(jù)庫,執(zhí)行后斷開數(shù)據(jù)庫連接,為了避免在每個測試方法中編寫同樣的代碼,我們可以使用 setUp 和 tearDown 方法,比如:

# -*- coding: utf-8 -*-

import unittest

class TestStringMethods(unittest.TestCase):

    def setUp(self):                              # 在每個測試方法執(zhí)行前被調用
        print 'setUp, Hello'

    def tearDown(self):                           # 在每個測試方法執(zhí)行后被調用
        print 'tearDown, Bye!'

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')    # 判斷兩個值是否相等

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())          # 判斷值是否為 True
        self.assertFalse('Foo'.isupper())         # 判斷值是否為 False

    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)

看看執(zhí)行結果:

$ python -m unittest -v mytest
test_isupper (mytest.TestStringMethods) ... setUp, Hello
tearDown, Bye!
ok
test_split (mytest.TestStringMethods) ... setUp, Hello
tearDown, Bye!
ok
test_upper (mytest.TestStringMethods) ... setUp, Hello
tearDown, Bye!
ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

小結

  • 通過從 unittest.TestCase 繼承來編寫測試類。
  • 使用斷言方法判斷程序運行的結果是否和預期相符。
  • setUp 在每個測試方法執(zhí)行前被調用,tearDown 在每個測試方法執(zhí)行后被調用。

參考資料

上一篇:迭代器 (Iterator)下一篇:字符串