Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何模拟一个非';你不叫名字吗?_Python_Mocking_Pytest_Python Decorators_Pytest Mock - Fatal编程技术网

Python 如何模拟一个非';你不叫名字吗?

Python 如何模拟一个非';你不叫名字吗?,python,mocking,pytest,python-decorators,pytest-mock,Python,Mocking,Pytest,Python Decorators,Pytest Mock,假设我有一个装饰器,它收集它装饰的所有函数,以便在将来的某个时候调用 mydecorator.py class CallLater(object): funcs = [] def __init__(self, func): self.funcs.append(func) @classmethod def call_now(cls, *args, **kwargs): for func in cls.funcs:

假设我有一个装饰器,它收集它装饰的所有函数,以便在将来的某个时候调用

mydecorator.py

class CallLater(object):
    funcs = []

    def __init__(self, func):
        self.funcs.append(func)

    @classmethod
    def call_now(cls, *args, **kwargs):
        for func in cls.funcs:
            func(*args, **kwargs)
import logging

from mydecorator import CallLater

logging.basicConfig(level=logging.INFO) 

@CallLater
def log_a():
    logging.info("A")

@CallLater
def log_b():
    logging.info("B")

def log_c():
    logging.info("C")
import logging
import pytest

from mymodule import log_a, log_c
from mydecorator import CallLater

logging.basicConfig(level=logging.INFO) 
pytest_plugins = ('pytest_mock',)

def test_mocking(mocker, caplog):
    mocker.patch('mymodule.log_b', log_c)

    CallLater.call_now()

    logs = [rec.message for rec in caplog.records]
    assert logs == ["A", "C"]
然后,我在一个模块中有一个函数,其中一个将由我的decorator保存

mymodule.py

class CallLater(object):
    funcs = []

    def __init__(self, func):
        self.funcs.append(func)

    @classmethod
    def call_now(cls, *args, **kwargs):
        for func in cls.funcs:
            func(*args, **kwargs)
import logging

from mydecorator import CallLater

logging.basicConfig(level=logging.INFO) 

@CallLater
def log_a():
    logging.info("A")

@CallLater
def log_b():
    logging.info("B")

def log_c():
    logging.info("C")
import logging
import pytest

from mymodule import log_a, log_c
from mydecorator import CallLater

logging.basicConfig(level=logging.INFO) 
pytest_plugins = ('pytest_mock',)

def test_mocking(mocker, caplog):
    mocker.patch('mymodule.log_b', log_c)

    CallLater.call_now()

    logs = [rec.message for rec in caplog.records]
    assert logs == ["A", "C"]
现在,如果我导入
mymodule
并调用
CallLater.call_Now()
,将调用
log_a
log_b
。但假设在测试期间,我希望用
log\u c
替换
log\u b
。我会试着用一个模拟来替换

mock_test.py

class CallLater(object):
    funcs = []

    def __init__(self, func):
        self.funcs.append(func)

    @classmethod
    def call_now(cls, *args, **kwargs):
        for func in cls.funcs:
            func(*args, **kwargs)
import logging

from mydecorator import CallLater

logging.basicConfig(level=logging.INFO) 

@CallLater
def log_a():
    logging.info("A")

@CallLater
def log_b():
    logging.info("B")

def log_c():
    logging.info("C")
import logging
import pytest

from mymodule import log_a, log_c
from mydecorator import CallLater

logging.basicConfig(level=logging.INFO) 
pytest_plugins = ('pytest_mock',)

def test_mocking(mocker, caplog):
    mocker.patch('mymodule.log_b', log_c)

    CallLater.call_now()

    logs = [rec.message for rec in caplog.records]
    assert logs == ["A", "C"]
但是当我运行
pytest
时,我发现我的mock没有工作

FAILED mock_test.py::test_mocking - AssertionError: assert ['A', 'B'] == ['A', 'C']

我认为
'mymodule.log_b'
是错误的模拟目标,因为它没有被调用为
mymodule.log_b()
,但我不确定在这种情况下应该使用什么。任何建议都将不胜感激

这是不可能的,问题是在加载时功能已经分配给列表。我能看到的唯一修补方法是直接修补
CallLater.funcs
,这有点尴尬,因为您必须手动将
log\u b
替换为
log\u c
,但它是这样的:

import logging
from unittest import mock

from mymodule import log_c
from mydecorator import CallLater

logging.basicConfig(level=logging.INFO)


def test_mocking(caplog):
    funcs = [log_c if f.__name__ == 'log_b' else f for f in CallLater.funcs]
    with mock.patch.object(CallLater, 'funcs', funcs):
        CallLater.call_now()

        logs = [rec.message for rec in caplog.records]
        assert logs == ["A", "C"]

请注意,您不能直接与函数进行比较(例如,
f==log\u b
),因为
log\u b
是修饰函数,而不是保存在
CallLater.funcs
中的函数

这很有道理。我没有考虑创建函数列表的时间。感谢您快速清晰的回复!很高兴我能帮忙!作为参考,这个问题的灵感来自于想要禁用,通过调用
sqlalchemy.event.remove
似乎可以更好地处理这个问题,如中所示