是否可以模拟一个可能在被测试的类中实例化的对象,该对象不使用依赖注入,并且将根据用于被测试类的c-tor而使用不同的构造函数进行实例化?
答案 0 :(得分:1)
你的模拟实际上并没有调用构造函数。他们调用一个代理对象,它将解析为该对象类型,但注入了许多运行时实用程序,以便您检查它。
如果您想要来测试构造函数,那么您可能希望在没有模拟的情况下实际实例化它。
答案 1 :(得分:1)
将构造函数调用视为静态调用:如果在代码中调用new Foo(...)
,Mockito将无法提供替换或模拟Foo
(至少在不重写系统的情况下) -under-test,which is what Powermock can do)。无论Foo有多少构造函数,都是如此。
如果你不允许改变被测系统,你就会陷入困境:它不是一个灵活的系统。这不一定是坏事:如果您的系统依赖是轻量级和弹性的,那么您可以确保依赖性经过充分测试,并将其视为您的被测系统的不可更改的实现细节。
如果你想用mock替换你的实例,你可能需要插入一个测试接缝,你可以进入并替换实例,这是一种依赖注入。您可以选择使用工厂,可以将其保存为字段或作为构造函数参数传递:
class YourSystemUnderTest {
interface FooFactory {
Foo create(Bar bar); // one-arg constructor
Foo create(Bar bar, Baz baz); // two-arg constructor
}
class DefaultFooFactory implements FooFactory {
@Override public Foo create(Bar bar) { return new Foo(bar); }
@Override public Foo create(Bar bar, Baz baz) { return new Foo(bar, baz); }
}
/** Visible and non-final for testing. */
FooFactory fooFactory = new DefaultFooFactory(); // replace this in tests
// ...
}
或者,作为一种稍微苛刻的方法,在您的测试系统中委托一个可覆盖的方法调用,并在测试中覆盖它。
class YourSystemUnderTest {
/** Visible and non-final for overriding. */
Foo createFoo(Bar bar) { return new Foo(bar); }
/** Visible and non-final for overriding. */
Foo createFoo(Bar bar, Baz baz) { return new Foo(bar, baz); }
}
class YourSystemUnderTest_Test {
@Mock Foo mockFoo;
@Before void createSystemUnderTest() {
yourSystemUnderTest = new YourSystemUnderTest() {
@Override Foo createFoo(Bar bar) { return mockFoo; }
@Override Foo createFoo(Bar bar, Baz baz) { return mockFoo; }
};
}
// ...
}
请注意,在这两种情况下,您都准确地表示YourSystemUnderTest不再仅使用真正的Foo实例锁定,而是允许使用其他Foo实现(包括测试双实现)。在测试之外,如果您升级或更改被测系统的依赖项,这可能会派上用场。