0

我正在使用 testng 和 Mockito2 为项目编写模块测试。我想模拟一些发出出站请求的方法。现在,要模拟的对象是在另一个对象的方法中本地创建的。所以,如果我说 4 个类,A、B、C 和 D,这样 A 创建 B 类型的对象,B 创建 C 类型的对象,依此类推,D 类型的对象要被模拟,我看到我有两个选择来模拟它。

选项 1 是监视 A、B、C 类型的对象,并将 B 的间谍注入 A 和 C 注入 B,最后在对象创建期间将 D 的模拟注入 C。下面是一个例子。

class A {
        public B createB()
        {
            retrun new B();
        }
        public void someMethod ()
        {
            B b = createB();
        }
    }

通过这种方式,我可以在调用 createB 时监视 A 并为 B 注入模拟对象。这样我最终可以模拟 D。

选项 2 是不模拟间歇性课程,而是直接拥有一个工厂类,如下所示:

class DFactory {
    private static D d;
    static public void setD (D newD)
    {
         d = newD;
    }
    public static D getD()
    {
        if (d!=null)
        {
            return d;
        } else
        {
            return new D();
        }
    }
}

上面的选项很简单,但我不确定这是否是正确的做法,因为它创建了更多静态方法,我相信应该避免这种情况。

我想知道应该首选哪种方法以及是否有其他替代方法。

请注意,我不希望使用 powermockito 或任何其他鼓励糟糕代码设计的框架。我想坚持使用mockito2。我可以重构我的代码以使其更具可测试性。

4

1 回答 1

0

你现在拥有它的方式,A 创建 B,B 创建 C,C 创建 D,所有这些创建都是您无法看到或更改的实现细节,特别是依赖对象的创建

您避免使用 PowerMockito 令人钦佩,并且您也非常有兴趣重构代码以很好地处理此更改,这意味着将 D 的选择委托给 A 的创建者。尽管我理解您的意思只是让这种选择发生在测试中,但语言并不知道这一点;您正在为依赖项选择不同的实现,并从 C 的实现中选择。这称为控制反转依赖注入。(你可能以前听说过它们,但我在最后介绍了这些术语,因为它们通常与当前对话中并不真正需要的重量和框架相关联。)

这有点棘手,因为看起来您不仅需要 D 的实现,还需要创建 D 的新实现。这使事情变得有点困难,但难度不大,尤其是如果您能够使用 Java 8 个 lambda 表达式和方法引用。在下面的任何地方,您都会看到对 的引用D::new,这是对 D 构造函数的方法引用,可以作为Supplier<D>参数接受。

我将通过以下方式之一重组您的课程:

  • 构造 A like new A(),但在实际调用 A 时保留对 D 实现的控制, like aInstance.doSomething(new D())or aInstance.doSomething(D::new)。这意味着每次调用方法时,C 都会委托给调用者,从而为调用者提供更多控制权。当然,您可以选择提供aInstance.doSomething()内部调用的重载aInstance.doSomething(new D()),以简化默认情况。
  • 构造 A like new A(D::new),其中 A 调用new B(dSupplier),B 调用new C(dSupplier)。这使得在单元测试中替换 B 和 C 变得更加困难,但是如果唯一可能的更改是让网络堆栈由 D 表示,那么您只是根据用例的需要更改代码。
  • 构造 A like new A(new B(new C(D::new)))。这意味着 A 只涉及其直接合作者 B,并且更容易将 B 的任何实现替换到 A 的单元测试中。这假设 A 只需要 B 的单个实例而不需要创建它,这可能不是一个好的假设;如果所有类都需要为其子级创建新实例,则 A 将接受 a Supplier<B>,并且 A 的构造看起来像new A(() -> new B(() -> new C(D::new)))。这是紧凑但复杂的,您可能会选择创建一个 AFactory 类来管理 A 的创建及其依赖项的配置。

如果第三个选项对您很有吸引力,并且您认为您可能想要自动生成一个像 AFactory 这样的类,请考虑研究像GuiceDagger这样的依赖注入框架

于 2018-06-28T19:27:10.410 回答