如果我有以下架构......
请注意以下修改内容。我(在最近的一些重构之后)发现在三个不同的文件中实际上有三个类。对不起,文件/类名变得荒谬了。我向你保证那些不是真名。 :)
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。
事实上,我无法找到任何正在做这件事的人的例子,这意味着以下两点之一:
......我认为它是第一...
完全公开,单元测试不是我熟练的。我的内部工具开发团队正在努力赶上我们的游戏,这是一项努力。我可能没有考虑正确测试。
任何想法都会受到欢迎。提前谢谢!
解!!!
感谢@ 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
块内(' sa挂在那个部分上的任何人的上下文管理器)引用类对象DependentDependentClass
的任何内容实际上都会引用MockDependentDependentClass
。
答案 0 :(得分: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:如果你需要模拟被测模块的依赖关系,那么它可能暗示你没有在正确的级别进行测试。