1

我正在尝试模拟实用程序类的几个组件。虽然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()测试场景中的代码。

4

2 回答 2

3

这是一个棘手的问题。

问题是api测试类在修补之前导入的类。来自补丁的文档:

目标是在执行装饰函数时导入的,而不是在装饰时。

api由于您首先在测试类中导入了该类,因此在您运行测试时该人没有得到修补。Python 认为它已经被导入。

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

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

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

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

于 2019-05-29T15:25:30.067 回答
0

在找到这个 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()
于 2019-05-31T09:47:56.397 回答