嵌套多个依赖项时如何模拟Python类

问题描述 投票:0回答:1

如果我有以下架构......

请注意以下编辑。我(在最近的一些重构之后)发现在三个不同的文件中实际上有三个类。对不起,文件/类名变得荒谬了。我向你保证那些不是真名。 :)

main_class.py

class MainClass(object):
    def do_some_stuff(self):
        dependent_class = DependentClass()



dependent_class.py

class DependentClass(object):
    def __init__():
        dependent_dependent_class = DependentDependentClass()
        dependent_dependent_class.do_dependent_stuff()



dependent_dependent_class.py

class DependentDependentClass(object):
    def do_dependent_stuff(self):
        print "I'm gonna do production stuff that I want to mock"
        print "Like access a database or interact with a remote server"

class MockDependentDependentClass(object):
    def do_dependent_stuff(self):
        print "Respond as if the production stuff was all successful."

我想在测试期间调用main_class.do_some_stuff,但是在执行期间,我希望用DependentDependentClass替换MockDependentDependentClass的实例,我怎样才能使用最佳实践进行pythonically。

目前,我能想到的最好的事情是根据环境变量的存在/值有条件地实例化一个类或另一个类。它确实有效但很脏。

我花了一些时间阅读有关unittest.mock和mock.patch函数的内容,看起来他们似乎能够提供帮助,但我可以解开的每个描述似乎与我的实际用例略有不同。

关键是我不想定义模拟返回值或属性,但我希望全局更改名称空间,我想,当我的应用程序认为它实例化DependentClass时,它实际上是实例化MockDependentClass。

事实上,我找不到任何人这样做的例子意味着两件事之一:

  1. 这是因为我是以一种非常愚蠢/天真的方式来做这件事。
  2. 我正在做一些天才,没有其他人遇到过它。

......我认为它是1号......

完全披露,单元测试不是我熟练的。我的内部工具开发团队正在努力赶上我们的游戏步骤。我可能没有考虑正确测试。

任何想法都会受到欢迎。先感谢您!

解!!!

感谢@ de1的帮助。鉴于我上面显示的聪明架构,以下内容实现了我想要的。

以下代码位于main_class.py

import dependent_class
from dependent_dependent_class import MockDependentDependentClass

with patch.object(dependent_class, "DependentDependentClass", MockDependentDependentClass):
    main_class = MainClass()
    main_class.do_some_stuff()

代码似乎(并且如果我知道它是如何做的那样)在模块dependent_class中操作命名空间,以便在with块内部(这是挂起在该部分上的任何人的上下文管理器)引用该类的任何内容对象DependentDependentClass实际上将引用MockDependentDependentClass

python python-2.7 unit-testing testing mocking
1个回答
1
投票

在这种情况下,mock module确实看起来确实很合适。您可以指定在调用各种patch方法时使用的mock(您的模拟)。

如果只导入类而不是模块,则可以在DependentClass中修补导入的DependentDependentClass:

import .DependentClass as dependent_class
from .DependentDependentClass import MockDependentDependentClass

with patch.object(dependent_class, 'DependentDependentClass', MockDependentDependentClass):
  # do something while class is patched

或者:

with patch('yourmodule.DependentClass.DependentDependentClass', MockDependentDependentClass):
  # do something while class is patched

或者以下内容仅在您通过模块访问类或在修补后导入类时才有效:

with patch('yourmodule.DependentDependentClass.DependentDependentClass', MockDependentDependentClass):
  # do something while class is patched

只是想到什么对象正在修补,何时。

注意:您可能会发现在较小的情况下命名文件时不那么容易混淆,与嵌入式类略有不同。

注意2:如果您需要模拟受测试模块的依赖关系,那么它可能表明您没有在正确的级别进行测试。

© www.soinside.com 2019 - 2024. All rights reserved.