如何避免测试中重复的代码并避免嘲笑自己?

发布于 2024-07-07 11:15:44 字数 1376 浏览 6 评论 0原文

在我的问题中 作为“mockist”TDD实践者,我应该在与被测方法相同的类中模拟其他方法吗?, 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 方法返回模拟的 dirpath 方法返回的内容)。

但是,如果我在测试spec_filepath时不模拟spec_dirpath,如何避免在spec_filepath测试中从spec_dirpath代码复制相同的测试代码? 如果我在测试 get_components 时不模拟spec_filepath,如何避免从spec_filepath spec_dirpath 复制测试代码?

In my question As a “mockist” TDD practitioner, should I mock other methods in the same class as the method under test?, Avdi answered "Personally I think that mocking on self is almost always a code smell. It's testing the implementation rather than the behavior." He may be right, but often I can't distinguish between the implementation and the behavior.

I have another example (in Python-style pseudo-code) that may lead to helpful answers:

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())

The idea here is that the get_components method calls the spec_filepath method in order to get a path to a file that the get_components_from_spec_file Components class method will read a list of components from. The spec_filepath method in turn calls spec_dirpath, which syncs the directory containing the spec file from the VCS system and returns the path to that directory. (Try not to look for bugs in this code--it's pseudo-code, after all.)

I'm looking for advice on how to test these methods...

Testing spec_dirpath should be quite straightforward. I can mock the VCS class and have it return a mock object and confirm the appropriate methods are called (and that the spec_dirpath method returns what the mock's dirpath method returns).

But if I don't mock spec_dirpath while testing spec_filepath, how do I avoid duplicating the same test code from the spec_dirpath code in the spec_filepath test? And if I don't mock spec_filepath while testing get_components, how do I avoid duplicating the test code from both spec_filepath and spec_dirpath?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不甘平庸 2024-07-14 11:15:44

单元测试通过某种形式的依赖注入效果更好。 在这种情况下,因为您在代码中创建客户端,所以您在测试中创建了一个依赖项,需要某种形式的动态模拟来应对。 (在这种情况下,我们将使用部分模拟来模拟创建依赖项的调用,以避免也测试这些依赖项)。

如果您在启动时注入依赖项(即传递客户端对象),那么您可以轻松地模拟它,并且仅测试一个类不会遇到重大困难。

因此,您需要部分模拟或依赖项注入解决方案来满足这些目标。

Unit testing works better with some form of dependency injection. In this case because you are creating the Client in the code you create a dependency in your test that requires some form of dynamic mock to cope with. (We'd use a partial mock in this case to mock our calls that create dependencies to avoid having to test those dependencies as well).

If you inject the dependency on startup (i.e. Pass in a client object) then you can mock it easily and not have major difficulties testing just the one class.

So you need either a partial mock or a dependency injection solution to meet those objectives.

故人如初 2024-07-14 11:15:44

通常在单元测试中,行为是指外部可观察到的行为。

使用您的示例,可观察的行为将是您从 get 返回的组件列表。 它们来自文件的事实是实现,因此我建议围绕您返回的组件列表构建测试,而不要模拟文件检索,因为它是类的内部,并使用设置代码来提供适当的文件。

另一种方法是制作从类的依赖项加载组件的文件,例如,将其制作为构造函数参数或方法参数,以允许在类外部指定该文件。 在这种情况下,它将是外部的,因此我会模拟它以确保您从中获得一致的行为,以确保您的班级正确使用它。

Usually in unit testing, behaviour refers to externally observable behaviour.

Using your example the observable behaviour would be the list of components that you get back from get. The fact that they come from a file is implementation, so I would advise building your tests around the list of components you get back without mocking the file retrieval as it is internal to the class, with setup code to provide an appropriate file.

The alternative would be to make the file which the components were loaded from a dependency for the class, e.g. make it a constructor parameter or method parameter, to allow the file to be specified externally to the class. In this case it would be external and so I would mock it to ensure you got consistent behaviour from it to ensure you're class was using it correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文