有没有一种简单的方法,使用 Mockito,在请求另一个模拟类或覆盖测试类加载器时加载另一个模拟类?
基本上我有一个类Foo,里面有一个成员"ClassA"。我想替换在测试期间使用"TestClassA"而不是"ClassA"。我不想使用依赖注入,因为它对实际操作没有任何意义。(它永远不能是A类以外的任何东西)
我可以这样做吗?
它永远不可能是A类以外的任何东西
。除了它是,在你的测试中。测试代码是真正的代码,虽然这并不意味着它应该潜入你的生产应用程序,但它确实意味着你需要为它的所有用例编写所需的灵活性,包括测试。
Mockito通过子类工作:由mock(Foo.class)
或@Mock Foo mockFoo
创建的mockFoo
实际上是Mockito创建的代理子类,它覆盖了Foo的每个方法。从该描述中可以看出,Mockito因此无法更改每个Foo对象的行为,尤其是无法更改从new Foo()
返回的对象的类型。
你有两个选择,我可以看到:
接受其中一个构造函数中的 ClassA 或 InterfaceA 实例。如果您将测试放在与待测试类相同的 Java 包中(即使在不同的源代码树中),您甚至可以将构造函数包设为私有,或者将其保持私有并创建一个静态工厂方法,如
createForTest(ClassA)
.例:
public class ConsumerToTest { private final ClassA classA; /** For public use. */ public ConsumerToTest() { this(new ClassA()); } /** For use in tests. */ ConsumerToTest(ClassA class) { this.classA = classA; } // ... }
使用PowerMock,它具有称为PowerMockito的Mockito集成。虽然 Mockito 使用纯代理子类和代码生成,但 PowerMockito 实际上重写了被测系统的字节码。这意味着你可以模拟静态方法和构造函数,而 Mockito 无法通过多态性自行调整。
就我个人而言,我非常喜欢解决方案1:代码由您控制,只要您清楚您的测试是被测系统的一流消费者,您就可以自由地将其设计为可测试。
通过构造函数来做是我更喜欢的。
例如
public class Foo {
private ClassA classA;
public Foo(ClassA classA) {
this.classA = classA;
}
}
public class FooTest {
private Foo foo;
@before
public void setup() {
foo = new Foo(Mockito.mock(ClassA.class);
}
}
使用 Mockito
执行此操作非常简单。
public class Foo {
private ClassA classA;
}
测试将如下所示:
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@Mock
private ClassA classA;
@InjectMocks
private Foo foo = new Foo();
//Test methods
}
就是这样,你嘲笑了A级!