官方文檔 : https://docs.python.org/dev/library/unittest.mock.html
Mock
Mock類庫(kù)是一個(gè)專門用于在unittest過程中制作(偽造)和修改(篡改)測(cè)試對(duì)象的類庫(kù)达吞,制作和修改的目的是避免這些對(duì)象在單元測(cè)試過程中依賴外部資源(網(wǎng)絡(luò)資源,數(shù)據(jù)庫(kù)連接,其它服務(wù)以及耗時(shí)過長(zhǎng)等).
安裝
Python 2.7中沒有集成mock庫(kù),Python3中的unittest中集成了mock庫(kù).
Python 2.7環(huán)境下pip安裝:
$ pip install mock
快速使用
>>> from mock import MagicMock #MagicMock為Mock的子類
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
#指定返回3
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')
#斷言輸入是否為3,4,5,key='value',否則報(bào)錯(cuò)
示例
#module.py
class Count():
def add(self, a, b):
return a + b
測(cè)試用例:
from unittest import mock
import unittest
from module import Count
class MockDemo(unittest.TestCase):
def test_add(self):
count = Count()
count.add = mock.Mock(return_value=13, side_effect=count.add)
result = count.add(8, 8)
print(result)
count.add.assert_called_with(8, 8)
self.assertEqual(result, 16)
if __name__ == '__main__':
unittest.main()
count.add = mock.Mock(return_value=13, side_effect=count.add)
side_effect參數(shù)和return_value是相反的芽世。它給mock分配了可替換的結(jié)果语御,覆蓋了return_value遂跟。簡(jiǎn)單的說户辱,一個(gè)模擬工廠調(diào)用將返回side_effect值咒钟,而不是return_value卢肃。
所以疲迂,設(shè)置side_effect參數(shù)為Count類add()方法,那么return_value的作用失效莫湘。
測(cè)試依賴
例如尤蒿,我們要測(cè)試A模塊,然后A模塊依賴于B模塊的調(diào)用幅垮。但是优质,由于B模塊的改變,導(dǎo)致了A模塊返回結(jié)果的改變军洼,從而使A模塊的測(cè)試用例失敗巩螃。其實(shí),對(duì)于A模塊匕争,以及A模塊的用例來說避乏,并沒有變化,不應(yīng)該失敗才對(duì)甘桑。
通過mock模擬掉影響A模塊的部分(B模塊)拍皮。至于mock掉的部分(B模塊)應(yīng)該由其它用例來測(cè)試。
# function.py
def add_and_multiply(x, y):
addition = x + y
multiple = multiply(x, y)
return (addition, multiple)
def multiply(x, y):
return x * y
然后跑杭,針對(duì) add_and_multiply()函數(shù)編寫測(cè)試用例铆帽。func_test.py
import unittest
import function
class MyTestCase(unittest.TestCase):
def test_add_and_multiply(self):
x = 3
y = 5
addition, multiple = function.add_and_multiply(x, y)
self.assertEqual(8, addition)
self.assertEqual(15, multiple)
if __name__ == "__main__":
unittest.main()
add_and_multiply()函數(shù)依賴了multiply()函數(shù)的返回值。如果這個(gè)時(shí)候修改multiply()函數(shù)的代碼德谅。
def multiply(x, y):
return x * y + 3
python3 func_test.py
F
======================================================================
FAIL: test_add_and_multiply (main.MyTestCase)
Traceback (most recent call last):
File "fun_test.py", line 19, in test_add_and_multiply
self.assertEqual(15, multiple)
AssertionError: 15 != 18
Ran 1 test in 0.000s
FAILED (failures=1)
測(cè)試用例運(yùn)行失敗了爹橱,然而,add_and_multiply()函數(shù)以及它的測(cè)試用例并沒有做任何修改窄做,罪魁禍?zhǔn)资莔ultiply()函數(shù)引起的愧驱,我們應(yīng)該把 multiply()函數(shù)mock掉。
import unittest
from unittest.mock import patch
import function
class MyTestCase(unittest.TestCase):
@patch("function.multiply")
def test_add_and_multiply2(self, mock_multiply):
x = 3
y = 5
mock_multiply.return_value = 15
addition, multiple = function.add_and_multiply(x, y)
mock_multiply.assert_called_once_with(3, 5)
self.assertEqual(8, addition)
self.assertEqual(15, multiple)
if __name__ == "__main__":
unittest.main()
@patch("function.multiply")
patch()裝飾/上下文管理器可以很容易地模擬類或?qū)ο笤谀K測(cè)試椭盏。在測(cè)試過程中组砚,您指定的對(duì)象將被替換為一個(gè)模擬(或其他對(duì)象),并在測(cè)試結(jié)束時(shí)還原掏颊。
這里模擬function.py文件中multiply()函數(shù)糟红。
def test_add_and_multiply2(self, mock_multiply):
在定義測(cè)試用例中,將mock的multiply()函數(shù)(對(duì)象)重命名為 mock_multiply對(duì)象。
mock_multiply.return_value = 15
設(shè)定mock_multiply對(duì)象的返回值為固定的15盆偿。
ock_multiply.assert_called_once_with(3, 5)
檢查ock_multiply方法的參數(shù)是否正確柒爸。