簡體   English   中英

如何模擬同名模塊內部函數中調用的函數?

[英]How to mock a function called in a function inside a module with the same name?

我正在嘗試使用unittest.mock ,但是出現錯誤:

AttributeError:沒有屬性“ get_pledge_frequency”

我具有以下文件結構:

pledges/views/
├── __init__.py
├── util.py
└── user_profile.py
pledges/tests/unit/profile
├── __init__.py
└── test_user.py

內部pledges/views/__init___.py我有:

from .views import *
from .account import account
from .splash import splash
from .preferences import preferences
from .user_profile import user_profile

在內部, user_profile.py我有一個名為user_profile的函數,該函數在util.py內部調用了一個名為get_pledge_frequency的函數,如下所示:

def user_profile(request, user_id):
    # some logic

    # !!!!!!!!!!!!!!!!
    a, b = get_pledge_frequency(parameter) # this is the function I want to mock

    # more logic

    return some_value

我在test_user.py內部進行了如下測試:

def test_name():
    with mock.patch(
        "pledges.views.user_profile.get_pledge_frequency"
    ) as get_pledge_frequency:
        get_pledge_frequency.return_value = ([], [])
        response = c.get(
            reverse("pledges:user_profile", kwargs={"user_id": user.id})
            ) # this calls the function user_profile inside pledges.user_profile

     # some asserts to verify functionality

我已經檢查了其他問題,但是當有一個稱為模塊的函數被導入到__init__文件中時,答案沒有涵蓋。

那么,有什么辦法可以解決這個問題? 我基本上已經將文件user_profile.py重命名為profile ,然后將測試更改為引用此模塊中的函數,但是我想知道是否可以使函數和模塊保持相同的名稱。

事實證明,可以在同名模塊中模擬在函數內部調用的函數。 圍繞unittest.mock.patch()小包裝可以使這種情況發生:

碼:

from unittest import mock
import importlib

def module_patch(*args):
    target = args[0]
    components = target.split('.')
    for i in range(len(components), 0, -1):
        try:
            # attempt to import the module
            imported = importlib.import_module('.'.join(components[:i]))

            # module was imported, let's use it in the patch
            patch = mock.patch(*args)
            patch.getter = lambda: imported
            patch.attribute = '.'.join(components[i:])
            return patch
        except Exception as exc:
            pass

    # did not find a module, just return the default mock
    return mock.patch(*args)

使用方法:

代替:

mock.patch("module.a.b")

你需要:

module_patch("module.a.b")

這是如何運作的?

基本思想是嘗試從可能的最長模塊路徑到最短路徑開始的模塊導入,如果導入成功,則將該模塊用作修補對象。

測試代碼:

import module

print('module.a(): ', module.a())
print('module.b(): ', module.b())
print('--')

with module_patch("module.a.b") as module_a_b:
    module_a_b.return_value = 'new_b'
    print('module.a(): ', module.a())
    print('module.b(): ', module.b())

try:
    mock.patch("module.a.b").__enter__()
    assert False, "Attribute error was not raised, test case is broken"
except AttributeError:
    pass

module測試文件

# __init__.py
from .a import a
from .a import b


# a.py
def a():
    return b()

def b():
    return 'b'

結果:

module.a():  b
module.b():  b
--
module.a():  new_b
module.b():  b

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM