【问题标题】:Mocking a class vs. mocking its interface模拟一个类与模拟它的接口
【发布时间】:2012-03-02 20:04:15
【问题描述】:

对于单元测试,我需要模拟几个依赖项。其中一个依赖项是实现接口的类:

public class DataAccessImpl implements DataAccess {
    ...
}

我需要设置一个这个类的模拟对象,当提供一些指定的参数时,它会返回一些指定的值。

现在,我不确定的是,模拟接口或类是否更好,即

DataAccess client = mock(DataAccess.class);

对比

DataAccess client = mock(DataAccessImpl.class);

在测试方面有什么不同吗?首选的方法是什么?

【问题讨论】:

标签: java unit-testing junit mocking


【解决方案1】:

在您的情况下可能没有太大区别,但首选方法是模拟接口,通常如果您遵循 TDD(测试驱动开发),那么您甚至可以在编写实现类之前编写单元测试。因此,即使您没有具体的类DataAccessImpl,您仍然可以使用您的接口DataAccess 编写单元测试。

此外,mock 框架在模拟类方面有局限性,有些框架默认只模拟接口。

【讨论】:

  • 嗨@Kuldeep Jain,如果实现类有一个调用外部服务的方法(需要模拟)怎么办?我们不能模拟接口来测试它,对吧?我们必须模拟实现类来模拟这个方法。
【解决方案2】:

在大多数情况下,技术上没有区别,您可以模拟为类或接口。从概念上讲,使用接口更好,因为抽象更好。

【讨论】:

    【解决方案3】:

    这取决于。如果您的代码依赖于类而不是接口,则必须模拟该类以编写有效的单元测试。

    【讨论】:

    • 或者听测试并使代码依赖于接口,因为它可能应该这样做。
    • 这是错误的。如果你看到它不同,请解释。 TDD 甚至需要针对接口而不是实现的类进行测试。如果您的代码依赖于一个类而不是给定的接口,那么您还有另一个更大的问题。
    • @AnnaKlein 我的回答不是关于目标代码,而是关于单元测试。如果您的代码依赖于实现而不是接口(在现实世界中这是一种常见情况),并且您必须在其上编写一个 UT,您应该模拟该类,否则您的单元测试可能无法编译或根本不会不完整。
    【解决方案4】:

    您应该模拟界面,因为它有助于确保您遵守 Liskov Substitution Principal (https://stackoverflow.com/a/56904/3571100)。

    【讨论】:

    • 很有趣,你如何通过模拟界面来实现这一点?我可以模拟接口,但在类实现中我可以违反 Liskov Substitution。
    • @karlihnos 我提供的链接指出“函数 [...] 必须能够在不知情的情况下使用派生类的对象。”换句话说,我们应该对接口而不是实现进行编程。所以在被测类中,我们可以通过对接口的编程来帮助实现LSP。当然,这样做并不能说明任何模拟接口实现是否会遵守 LSP。
    【解决方案5】:

    如果你只是通过界面使用它,它不是一个部分的模拟,除了你的内心感受之外没有什么区别。如果类有未使用的公共方法,则模拟类也会模拟未使用的公共方法,但这没什么大不了的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多