我如何修补一个对象,以便所有方法都被模拟,除了一个?
我有一个入口点函数将它称为main
对象,我想保持unmocked,因为它调用该对象上的其他几个方法:
class Thing(object):
def main(self):
self.alpha()
self.bravo()
def alpha(self):
self.charlie()
def bravo(self):
raise TypeError("Requires Internet connection!")
def charlie(self):
raise Exception("Bad stuff happens here!")
这是非常简单的手动模拟:
thing = Thing()
thing.alpha = MagicMock()
thing.bravo = MagicMock()
我可以测试以确保alpha和bravo都被调用一次,我可以在alpha和bravo中设置副作用以确保它们处理等。
是如果代码定义的变化我很担心,有人增加了charlie
调用main
。 它没有被嘲笑,所以现在会感觉到副作用(它们是写入文件,连接到数据库,从互联网获取东西的东西,所以简单的异常不会提醒我现在正在进行测试坏)。
我的计划是验证我的模拟对象除了我所说的应该调用的其他方法(或引发测试异常)之外,不会调用其他方法。 但是,如果我做这样的事情:
MockThing = create_autospec(Thing)
thing = Thing()
thing.main()
print thing.method_calls
# [calls.main()]
然后main
也被模拟,所以它不会调用其他方法。 我怎样才能嘲笑每种方法,但主要方法? (我想method_calls是[calls.alpha(), calls.bravo()]
)。
编辑:对于黑客答案
那么,我有一个非常冒险的解决方案,但我希望有一个比这更好的答案。 基本上我重新绑定了原始类的方法(Python绑定了一个未绑定的方法)
MockThing = create_autospec(Thing)
thing = MockThing()
thing.main = Thing.ingest.__get__(thing, Thing)
thing.main()
print thing.method_calls
# [calls.alpha(), calls.bravo()]
但是使用函数描述符必须有一个更简单的解决方案!
当我做了这些奇怪的东西,像调用一个真正的方法,我会模拟我曾经调用方法静态引用:
mt = Mock(Thing)
Thing.main(mt)
print(mt.mock_calls)
[call.alpha(), call.bravo()]
无论如何,在编写测试之后,最好通过使用一些合作者来区分你应该从你想测试的东西中分离出什么:使用这些测试来引导生产代码重构,最后重构你的测试以去除这些脏测试。
我遇到了同样的问题,但我想出了一个办法,让我满意。 下面的例子使用上面列出的Thing类:
import mock
mock_thing = mock.create_autospec(Thing)
mock_thing.main = lambda x: Thing.main(mock_thing, x)
这将导致mock_thing调用属于mock_thing的实际'main'函数,但mock_thing.alpha()和mock_thing.beta()将被称为mock! (用你传入函数的任何参数替换x)。
希望这对你有用!
看起来你要么让单元测试进入你的集成/功能测试,要么你担心测试除某个单元之外的其他东西。
如果你的单元测试Thing
,那么你应该嘲笑你没有测试部分。 但是如果你正在测试Thing
如何与其他事物(如数据库)集成,那么你应该测试你的实际Thing
,而不是一个嘲弄的Thing
。
而且,这是依赖注入非常有意义的地方,因为你可以这样做:
class Thing:
def __init__(self, db, dangerous_thing):
self.db = db
self.dangerous_thing = dangerous_thing
#....
def charlie(self):
foxtrot = self.dangerous_thing.do_it()
现在,您可以在测试时通过模拟dangerous_thing
Thing
,因此您不必担心真正做到dangerous_thing
事情。
上一篇: How do I patch an object so that all methods are mocked except one?
下一篇: What GHC optimization is responsible for duplicating case expressions?