【问题标题】:Mock a superclass constructor模拟超类构造函数
【发布时间】:2018-10-27 02:08:30
【问题描述】:

我想知道我是否可以模拟超类构造函数调用及其 super() 调用。

例如,我有以下类

class A
{
    A(..)
    {
        super(..)
    }
}   

class B extends A
{
    B(C c)
    {
        super(c)
    }
}

所以,我打算对 B 类中的一些方法进行单元测试,但是在创建实例时,它确实调用了超类构造函数,这使得编写单元测试变得困难。那么,我怎样才能模拟所有的超类构造函数调用。我还想模拟 A 类中的一些方法,以便它返回一些我需要的值。

谢谢!!

【问题讨论】:

  • 是什么确切地使测试 B 变得困难?它调用超类构造函数的事实本质上没有问题。您应该尝试模拟 依赖项,而不是对象本身的行为。
  • 我讨论suppressing ctors using PowerMock with EasyMock in this blog post,我没有 Mockito 版本。不过,尚不清楚您是要消除 ctor 还是替换它。
  • @Jon Skeet。是的,我确实理解这一点,但为了实现这一点,它非常复杂,并在后台启动多个线程,调用我的单元测试不需要的许多外部依赖项。
  • 那么您应该注入这些依赖项,而不是在超级构造函数中创建它们。这就是重点。

标签: java junit guice mockito jmock


【解决方案1】:

您可以使用 PowerMock 库。当你需要完成像你这样的事情时,它真的是一个救星。 https://github.com/powermock/powermock/wiki/Suppress-Unwanted-Behavior

【讨论】:

  • 我不知道 PowerMock 库的那一部分。我仍然认为它指向一种“气味”,但仅仅因为某些东西很臭并不意味着你有能力真正清洁它。
【解决方案2】:

模拟构造函数是一个非常糟糕的主意。这样做是为了规避在生产中发生的行为。这就是为什么在构造函数中做的工作,比如启动线程和调用外部依赖,是design flaw

您能否诚实地说在构造函数中执行的工作对您尝试测试的行为没有影响?如果答案是否定的,您将冒着编写将在测试环境中通过但在生产中失败的测试的风险。如果答案是肯定的,那么将“工作”移到构造函数之外是一个简单的案例。另一种选择是将您尝试测试的行为移动到另一个类(可能是它自己的)。

如果您使用像 Guice 这样的 DI 框架(我假设是因为您以这种方式标记它),则更是如此。

【讨论】:

    【解决方案3】:

    您的问题的简短回答是“不完全正确”。您不能“模拟”构造函数,更不用说超级了。使用我熟悉的模拟框架也很难或不可能模拟 super.anyMethod。 Powermock 确实允许您抑制超级构造函数和有问题的方法,这与模拟它们不太一样,但可能会有所帮助。

    当 B 扩展 A 时,它当然与 A 完全耦合。这不是问题本身,但它可以,而且看起来就在这里。不要让 B 扩展 A,而是尝试让 B 包含一个 A(如果需要,可能实现相同的接口)。然后你可以注入一个模拟 A 并委托你想要的所有调用。那会更容易进行单元测试,不是吗?

    测试驱动开发的好处之一是您在测试期间发现设计中的这些内容。

    【讨论】:

    • 参见上面关于:PowerMock。不管这是否是个好主意,在运行时替换构造函数是可能的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2019-11-24
    • 2012-04-28
    • 1970-01-01
    • 2013-09-03
    • 2016-03-06
    • 1970-01-01
    相关资源
    最近更新 更多