我试图在我正在测试的类中模拟一个对象的方法。
例如
class ClassToTest {
public doSomething () {
SomeObject a = new SomeObject ();
a.doSomethingElse ();
}
}
有没有办法模拟变量“a”的方法?我希望 doSomethingElse 在测试期间什么都不做。我目前正在使用 Mockito,但我对任何模拟框架持开放态度。
谢谢
当然,通过一些重构是可能的:
class SomeObject {
public void doSomethingElse()
{
}
}
class ClassToTest
{
private final SomeObject someObject;
public void doSomething()
{
someObject.doSomethingElse();
}
public ClassToTest(SomeObject someObject)
{
this.someObject = someObject;
}
}
class Test {
@Test
public void testDoSomething()
{
SomeObject someObject = Mockito.mock(SomeObject.class);
new ClassToTest(someObject).doSomething();
Mockito.verify(someObject, Mockito.atLeastOnce()).doSomethingElse();
}
}
是的,有一种方法,如下面的JMockit测试所示:
public void testDoSomething(final SomeObject mock)
{
new ClassToTest().doSomething();
new Verifications() {{ mock.doSomethingElse(); }};
}
无需重构被测代码以使用包装器、DI 等;简单地嘲笑任何你需要被嘲笑的东西。
当它被声明为局部变量时,不可能模拟引用“a”,就像你的情况一样。您可以考虑将依赖项注入到 SomeObject,例如作为 doSomething 方法的参数。这样,您可以在测试中注入 SomeObject 的模拟。
依赖注入的好处之一是增加了可测试性。
我相信您可以使用EasyMock 2.5 或更早版本的 EasyMock 类扩展,并且显然它包含在 3.0 中。有关您尝试执行的操作的信息,请参阅上一页的这一部分。也就是说,我个人并没有尝试过这样做,所以我不知道它的效果如何。
class ClassToTest {
private SomethingElseInterface somethingElseDoer ;
public ClassToTest(SomethingElseInterface somethingElseDoer) {
this.somethingElseDoer = somethingElseDoer;
}
public doSomething () {
somethingElseDoer.doSomethingElse();
}
}
以及你在哪里使用它:
SomethingElseInterface somethingElseDoer = ...; // in a test, this is where you mock it
ClassToTest foo = new ClassToTest(somethingElseDoer); // inject through constructor
foo.doSomething();
如果您希望在每次调用中都有一个新实例,我建议您通过以下方式进行重构:
class ClassToTest {
public doSomething () {
SomeObject a = getInstance();
a.doSomethingElse ();
}
protected SomeObject getInstance() {
return new SomeObject();
}
}
然后,您可以创建一个扩展 ClassToTest 的测试类,覆盖 getInstance() 方法,并提供一个模拟对象。
这当然只有在您可以公开 getInstance() 方法时才可行,因此如果该类是公共 API 的一部分,我不建议这样做。如果是这种情况,请考虑使用依赖注入提供工厂类。