python3 unittest mock.patch 做用域

mock.patch 做用域

在使用 unittest.mock.patch 前必定要讀一下文檔,你百度出來的必定是最簡單的例子也沒有說明 patch 做用條件,只是訪官網寫的最簡單例子,若是你剛接觸 python unittest 可能會有很大一個坑在等着你python

unittest 官網文檔的關於 patcher 的第一句話很重要:api

The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class decorators.

stackoverflow 有個回答更容易理解一些:測試

patch works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.

The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.code

有時候認真看文檔也是一種水平,我開始忽略了第一句話,白白浪費了不少時間。下面我用例子來講明一下 patch 做用域:ip

假設我在 lib 模塊下邊有個類 Fooci

class Foo:

    def run(self):
        return 1

而後我在 api.bar 調用 Foo().run()作用域

# api.py 文件

from lib import Foo

def bar():
    instance = Foo()
    instance.run()

下邊咱們來寫 bar 的測試用例:文檔

from unittest.mock import patch
from api import bar

@patch('lib.Foo')
def test_bar1(mock_foo):
    """"
    這是個反例,這裏 mock 並無起到真正的做用
    """
    instance = mock_foo.return_value
    instance.run.return_value = 2
    print(bar().run()) # return 1
    assert bar().run() == 2 # False

@patch('api.Foo')
def test_bar2(mock_foo):
    instance = mock_foo.return_value
    instance.run.return_value = 2
    print(bar().run()) # return 2
    assert bar().run() == 2 # true
    assert bar() is instance

注意 test_bar1 mock 並無起到咱們所預期的做用, Foo().run() 依舊返回 1, 而 test_bar2 是咱們所預期的。get

test_bar1test_bar2 的區別在於 test_bar1 patch 的目標是 lib.Footest_bar2 patch 的目標是 api.Fooit

test_bar1test_bar2 就惟一的局別就是:@patch('lib.Foo') <==> @patch('api.Foo') ,能夠看出 patch target 參數是在運行處對目標進行一個替換,而不是替換源類

相關文章
相關標籤/搜索