在我的问题As a “mockist” TDD practitioner, should I mock other methods in the same class as the method under test?中,Avdi回答“我个人认为嘲笑自我几乎总是代码味道。它正在测试实现而不是行为。”他可能是对的,但我经常无法区分实施和行为。
我有另一个例子(在Python风格的伪代码中)可能会得到有用的答案:
class Consumer:
def spec_dirpath:
client = VCS.get_connection(self.vcs_client_name)
client.sync()
return client.dirpath()
def spec_filepath:
filepath = os.path.join(spec_dirpath(), self.spec_filename)
if not os.path.exists(filepath):
raise ConsumerException
return filepath
def get_components:
return Components.get_components_from_spec_file(self.spec_filepath())
这里的想法是get_components方法调用spec_filepath方法以获取get_components_from_spec_file Components类方法将从中读取组件列表的文件的路径。 spec_filepath方法依次调用spec_dirpath,它将包含来自VCS系统的spec文件的目录同步,并返回该目录的路径。 (尽量不要在这段代码中查找错误 - 毕竟它是伪代码。)
我正在寻找有关如何测试这些方法的建议......
测试spec_dirpath应该非常简单。我可以模拟VCS类并让它返回一个模拟对象并确认调用了适当的方法(并且spec_dirpath方法返回mock的dirpath方法返回的内容)。
但是如果我在测试spec_filepath时没有模拟spec_dirpath,我如何避免在spec_filepath测试中从spec_dirpath代码中复制相同的测试代码?如果我在测试get_components时没有模拟spec_filepath,我如何避免从spec_filepath 和 spec_dirpath复制测试代码?
答案 0 :(得分:1)
通常在单元测试中,行为是指外部可观察的行为。
使用您的示例,可观察行为将是您从get获取的组件列表。它们来自文件的事实是实现,所以我建议围绕你得到的组件列表构建测试,而不是模拟文件检索,因为它是类的内部,设置代码提供适当的文件。
另一种方法是根据类的依赖关系制作组件加载的文件,例如:使其成为构造函数参数或方法参数,以允许在类外部指定文件。在这种情况下,它将是外部的,所以我会嘲笑它以确保你得到一致的行为,以确保你的班级正确使用它。
答案 1 :(得分:1)
通过某种形式的依赖注入,单元测试效果更好。在这种情况下,因为您在代码中创建了客户端,所以您在测试中创建了一个依赖项,需要某种形式的动态模拟来应对。 (在这种情况下,我们使用部分模拟来模拟我们的调用,这些调用创建依赖关系以避免必须测试这些依赖项。)
如果您在启动时注入依赖项(即在客户端对象中传递),那么您可以轻松地模拟它,并且不会在仅测试一个类时遇到重大困难。
因此,您需要部分模拟或依赖注入解决方案才能实现这些目标。