我(仍然)尝试使用 PowerMockito 检查 bar(Alpha, Baz)
是否调用 bar(Xray, Baz)
(如 bar(Xray) , Baz)
是 private
) - 没有实际调用后者,因为我的 MCVE 类 Foo
下面。 (我经历了同一个类 earlier ,Foo
中的所有方法都是 public
- 如果您有似曾相识的感觉...)
public class Foo {
private String bar(Xray xray, Baz baz) {
return "Xray";
}
private String bar(Zulu zulu, Baz baz) {
return "Zulu";
}
public String bar(Alpha alpha, Baz baz) {
if(alpha.get() instanceof Xray) {
return bar((Xray)alpha.get(), baz);
} else if(alpha.get() instanceof Zulu) {
return bar((Zulu)alpha.get(), baz);
} else {
return null;
}
}
}
当我尝试运行下面的测试时,我从 PowerMock 得到一个 NPE:
@RunWith(PowerMockRunner.class)
// @PrepareOnlyThisForTest(Foo.class) // we aren't looking at the byte code, I think
public class FooTest {
@Test
public void testBar_callsBarWithXray() throws Exception {
Baz baz = new Baz(); //POJOs
Alpha alpha = new Alpha();
alpha.set(new Xray());
Foo foo = new Foo();
Foo stub = spy(foo); // using Mockito, as it's neither final nor "not spyable"
// NPE at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing(PowerMockitoStubberImpl.java:67)
PowerMockito.doReturn("ok").when(stub, "bar", Xray.class, Baz.class);
stub.bar(alpha, baz);
// Testing if bar(Xray, Baz) was called by bar(Alpha, Baz)
PowerMockito.verifyPrivate(foo).invoke("bar", Xray.class, Baz.class);
// Mockito's equivalent for a public method: verify(stub, times(1)).bar(any(Xray.class), any(Baz.class));
}
}
如果我将 stub 设置为 PowerMockito.spy(foo)
,我会收到 IllegalArgumentException: argument type mismatch at org.powermock.reflect.internal.WhiteboxImpl.performMethodInitation(WhiteboxImpl.java :2014)
相反。 (它与 NPE 在同一行冒泡。)
我正在使用 Mockito-core 1.9.5、PowerMock 1.5.4(module-junit4 和 api-mockito)和 JUnit 4.11。
我需要更改什么才能阻止抛出异常?我怎样才能让这个测试发挥作用? (除了 testing that 我的类(class)工作,而不是如何...;-))
最佳答案
在设置期望时,我们必须使用精确的参数匹配器。在你的情况下,它是 Matchers.any(Xray.class)、Matchers.any(Baz.class)
我已按如下方式修改了您的代码,并在测试方法的输出对象上添加了断言语句。
@RunWith(PowerMockRunner.class)
//@PrepareOnlyThisForTest(Foo.class) // we aren't looking at the byte code, I think
public class FooTest {
@Test
public void testBar_callsBarWithXray() throws Exception {
Baz baz = new Baz(); //POJOs
Alpha alpha = new Alpha();
alpha.set(new Xray());
Foo foo = new Foo();
Foo stub = PowerMockito.spy(foo); // using Mockito, as it's neither final nor "not spyable"
// NPE at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing(PowerMockitoStubberImpl.java:67)
PowerMockito.doReturn("ok").when(stub, "bar", Matchers.any(Xray.class), Matchers.any(Baz.class));
String res = stub.bar(alpha, baz);
Assert.assertEquals("ok", res);
//Testing if bar(Xray, Baz) was called by bar(Alpha, Baz)
PowerMockito.verifyPrivate(stub).invoke("bar", Matchers.any(Xray.class), Matchers.any(Baz.class));
// Mockito's equivalent for a public method: verify(stub, times(1)).bar(any(Xray.class), any(Baz.class));
}
}
观察:当调用验证方法时,我们必须传递 stub 对象而不是实际对象,因为我们对 stub 对象设置了期望。由于我添加了断言语句来测试该方法,因此您不必在 stub 上验证它是否正常工作。
添加: 我在公共(public)和私有(private)“bar”方法中添加了 sysout 语句,当我再次测试时,我发现公共(public) bar 方法的 sysout 语句没有打印。 这意味着上面的代码只模拟了公共(public)方法,而没有模拟私有(private)方法。
为了模拟私有(private)“bar”方法,我尝试使用 MemberMatcher.method 进行另一种模拟,效果非常好。
import org.powermock.api.support.membermodification.MemberMatcher;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Foo.class) // we need this
public class FooTest {
@Test
public void testBar_callsBarWithXray() throws Exception {
Baz baz = new Baz(); //POJOs
Alpha alpha = new Alpha();
alpha.set(new Xray());
Foo stub = PowerMockito.spy(new Foo());
PowerMockito.doReturn("ok")
.when(stub,
MemberMatcher.method(Foo.class,
"bar",
Xray.class, Baz.class))
.withArguments(Matchers.any(Xray.class), Matchers.any(Baz.class));
String res = stub.bar(alpha, baz);
Assert.assertEquals("ok", res);
//Testing if bar(Xray, Baz) was called by bar(Alpha, Baz)
PowerMockito.verifyPrivate(stub).invoke("bar", Matchers.any(Xray.class), Matchers.any(Baz.class));
// Mockito's equivalent for a public method: verify(stub, times(1)).bar(any(Xray.class), any(Baz.class));
}
output : public bar
测试方法也通过了。下面是具有 sysouts 的 foo 方法。
private String bar(Xray xray, Baz baz) {
System.out.println("private bar");
return "Xray";
}
public String bar(Alpha alpha, Baz baz) {
System.out.println("public bar");
if(alpha.get() instanceof Xray) {
return bar((Xray)alpha.get(), baz);
} else if(alpha.get() instanceof Zulu) {
return bar((Zulu)alpha.get(), baz);
} else {
return null;
}
}
关于java - PowerMockito 在尝试 stub 私有(private)重载方法时抛出 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32208501/