2

我(仍在)尝试检查是否使用 PowerMockitobar(Alpha, Baz)调用(原样) - 没有实际调用后者,因为我在下面的 MCVE 类。(我之前上过同一堂课,所有方法都在-以防你有似曾相识的感觉......)bar(Xray, Baz)bar(Xray, Baz)privateFooFoopublic

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));
    }
}

如果我制作存根 a PowerMockito.spy(foo),我会得到 a IllegalArgumentException: argument type mismatch at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:2014)。(它与 NPE 在同一条线上冒泡。)

我正在使用 Mockito-core 1.9.5、PowerMock 1.5.4(module-junit4 和 api-mockito)和 JUnit 4.11。

我需要改变什么来阻止异常被抛出?我怎样才能使这个测试工作?(除了测试我的课程是否有效,而不是如何...... ;-))

4

1 回答 1

2

在设置期望值时,我们必须使用精确的参数匹配器。在您的情况下,它是 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));
   }
}

观察:调用验证方法时,我们必须传递存根对象而不是实际对象,因为我们对存根对象设置了期望。当我添加断言语句来测试该方法时,您不必在存根上验证它是否正常工作。

添加: 我在公共和私有“bar”方法中添加了 sysout 语句,当我再次测试时,我看到公共 bar 方法的 sysout 语句没有打印。这意味着上面的代码只模拟了公共方法,而不是私有方法。

为了模拟私有 '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;
    }
}
于 2015-08-26T06:48:15.080 回答