2 回答
TA贡献1812条经验 获得超5个赞
我认为你可以重新考虑这个设计,记住两个概念:
Python 多重继承来设计你的类。
使用 super() 和 Python 的方法解析顺序 (MRO) 在测试代码中注入类依赖项的模拟。
关于第一点,您的类将如下所示:
# core.py
class Core:
def decide(self, data):
""" Makes decisions based on input data """
# blah blah
# tokenizer.py
class Tokenizer:
def tokenize(self, query):
""" Tokenize the input query string """
return query
# processor.py
# from tokenizer import Tokenizer
# from core import Core
class Processor(Core, Tokenizer):
def process(self, query):
"""
Send the input query to tokenizer
tokenized input is send to the Core module for decision making
"""
tokenized_input = super().tokenize(query)
super().decide(tokenized_input)
# listener.py
# from processor import Processor
class Listener(Processor):
def listen(self):
""" Continuosly listens to user input """
while True:
query=input()
super().process(query)
# bot.py
#from listener import Listener
class Bot(Listener):
def start_listener(self):
super().listen()
Bot().start_listener()
通过这种OO设计和super()的使用,我们可以利用MRO在类的依赖项中注入模拟,我将展示如何在SUT(被测主题)中为其依赖项注入模拟。
机器人和处理器的示例:
class MockCore(Core):
def decide(self, data):
""" Here you can implement the behavior of the mock """
class MockTokenizer(Tokenizer):
def tokenize(self, query):
""" Here you can implement the behavior of the mock """
return query
class ProcessorSut(Processor, MockCore, MockTokenizer):
'Here we are injecting mocks for Processor dependencies'
class Bot(Listener):
def start_listener(self):
super().listen()
class MockListener(Listener):
def listen(self):
""" Here you can implement the behavior of the mock """
return
class BotSut(Bot, MockListener):
'Here we are injecting a mock for the Listener dependency of Bot'
看到我们的SUT类的MRO,我们可以理解为什么多重继承和super()的使用允许我们以这种方式注入模拟。
机器人和处理器解决方案的结果 MRO:
Help on class BotSut in module __main__:
class BotSut(Bot, MockListener)
| Here we are injecting a mock for the Listener dependency of Bot
|
| Method resolution order:
| BotSut
| Bot
| MockListener
| Listener
| Processor
| Core
| Tokenizer
| builtins.object
...
...
Help on class ProcessorSut in module __main__:
class ProcessorSut(Processor, MockCore, MockTokenizer)
| Here we are injecting mocks for Processor dependencies
|
| Method resolution order:
| ProcessorSut
| Processor
| MockCore
| Core
| MockTokenizer
| Tokenizer
| builtins.object
TA贡献1943条经验 获得超7个赞
您可以将实用程序类设置为类属性:
class Core:
def decide(self, data):
return False
class Tokenizer:
def tokenize(self, query):
return [] # ...
class Processor:
tokenizer_class = Tokenizer
core_class = Core
def process(self, query):
tokenized_input = self.tokenizer_class().tokenize(query)
return self.core_class().decide(tokenized_input)
class Listener:
processor_class = Processor
def listen(self):
while True:
query = input()
self.processor_class().process(query)
然后,您可以使用测试框架的模拟/补丁功能,例如pytest的:monkeypatch
def test_foo(monkeypatch):
monkeypatch.setattr(Processor, 'tokenizer_class', FooTokenizer)
# etc...
添加回答
举报