繁体   English   中英

Python unittest.mock:调用了已修补的类方法,但断言失败

[英]Python unittest.mock: patched class method called but assertion fails

我正在尝试模拟实用程序类的几个组件。 尽管assert_called()对于一种方法是可以的,但对于另一种方法却是失败的,但是我敢肯定两者都可以被调用。 我正在Windows 10上运行Python 3.7.3。

我已将方案简化为基本要素。 实用程序类( util.py ):

class api:

    @staticmethod    
    def send(data):
        print("sending %s" % data)

    class logger:

        @staticmethod
        def info(s):
            print("INFO: %s" % s)

        @staticmethod
        def error(s):
            print("ERROR: %s" % s)

正常工作的单元测试变体:

import unittest
from unittest.mock import patch
from util import api

def do_something():
    api.logger.info("doing something")
    api.send("some data")

@patch("util.api.logger")
class Test(unittest.TestCase):

    def test_do_something(self, mock_logger):
        do_something()
        mock_logger.info.assert_called()

失败的那一个:

import unittest
from unittest.mock import patch
from util import api

def do_something():
    api.logger.info("doing something")
    api.send("some data")

@patch("util.api")
class Test(unittest.TestCase):

    def test_do_something(self, mock_api):
        do_something()
        mock_api.send.assert_called()

运行测试时,我同时获得两个print()输出:

INFO: doing something
sending some data

因此,我确定两种方法都可以调用。

很可能我犯了一些愚蠢的虚拟错误,因为我真的是python新手...

更多背景:

在我精简的场景中, do_something()只是一组功能的替代,这些功能是我测试的对象,而在我的实际场景中,这些功能实际上是在单独的python文件中定义的。 在生产环境中,它在提供实用程序类api的框架的上下文中运行。 在我的测试环境中, util.py本身是生产api的模拟。 像这样加载要测试的py文件(而不是def do_something(): ... ):

path = os.getcwd() + "<local path to py file to be tested>"
globals().update({ **runpy.run_path(path, init_globals=globals()), **globals() })

因此,我无法在测试方案中修改do_something()代码。

这是一个棘手的问题。

问题在于,修补程序之前,测试类已导入了api类。 从文档的补丁

在执行装饰功能时(而不是在装饰时)导入目标。

由于您首先将api类导入测试类中,因此在运行测试时不会修补该家伙。 Python认为它已经被导入。

请注意, logger类不是这种情况,因为您从不会导入它。 如果有的话,第一个测试也会失败。

最简单的修复-将导入移动到测试功能中。

def do_something():
     from util import api
     api.logger.info("doing something")
     api.send("some data")

现在, patch将执行导入-因此将模拟放置在测试范围中,而不是实际的类中。

找到这个SO问题之后终于得到了它-我不知道您也可以修补单个函数/类方法( unittest.mock.patch参考中未提及)。 所以这有效:

import unittest
from unittest.mock import patch
from util import api

def do_something():
    api.logger.info("doing something")
    api.send("some data")

@patch("util.api.send")
@patch("util.api.logger")
class Test(unittest.TestCase):

    def test_do_something(self, mock_logger, mock_send):
        do_something()
        mock_send.assert_called()
        mock_logger.info.assert_called()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM