[Python] 在 pytest 裡 monkey patch 系統內建的函式

[Python] 在 pytest 裡 monkey patch 系統內建的函式

今天在用 pytest 寫 unit-testing 程式時,遇到一個問題:

要如何 mock 掉 python 原本就提供的內建函式呢?

平常如果是像 urllib.quote() 這種函式,可以用下面的方法來 mock:

def test_mock(monkeypatch):
def mock_urllib_quote(s, safe="/"):
# Do something...
return "mocked result"
# Mock set_system_info
import urllib
monkeypatch.setattr(urllib, "quote", mock_urllib_quote)
assert urllib.quote("abc") == "mocked result"

 

不過,如果我今天想要 mock 的是像 open() 這種內建函式呢?

在用 open() 前,好像不用 import 某個特定模組… 

 

後來在網路上找到了解答,原來 open() 這類的內建函式是屬於 __builtin__ 模組的,

所以只要去 mock __builtin__ 模組就行囉~

def test_mock_open(monkeypatch):
# Mock open()
import __builtin__
monkeypatch.setattr(__builtin__, "open", mock_open)
f = open("test")
assert f.read() == ""
assert f.fileno() == 0

 

這邊定義了一個 mock_open(),我讓它傳回一個自己定義的 MockFileObj,

然後在裡面定義我想要的檔案讀寫行為:

class MockFileObj(object):
data = ""
def __init__(self):
pass
def __enter__(self):
return self
def __exit__(self, exit_type, msg, traceback):
pass
def read(self):
return MockFileObj.data
def readlines(self, size=0):
return []
def write(self, data):
MockFileObj.data += data
print "write [%s]" % (data)
def fileno(self):
return 0
def close(self):
pass
def mock_open(name, *args, **kwargs):
return MockFileObj()

 

參考資料:

pytest: Monkeypatching/mocking modules and environments

Mock python builtin functions in pytest

(本頁面已被瀏覽過 1,318 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料