尝试对私有重载方法进行存根时,PowerMockito抛出NullPointerException [英] PowerMockito throws NullPointerException when trying to stub private overloaded method

查看:257
本文介绍了尝试对私有重载方法进行存根时,PowerMockito抛出NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我(仍)尝试使用PowerMockito(因为bar(Xray, Baz)private)检查bar(Alpha, Baz)是否调用了bar(Xray, Baz)-鉴于下面的我的MCVE类Foo,没有实际调用后者. (我之前是同一类的 Foo中的所有方法都是public-如果您已经有了déjàvu ...)

I'm (still) trying to check if bar(Alpha, Baz) called bar(Xray, Baz) using PowerMockito (as bar(Xray, Baz) is private) - without actually calling the later, given my MCVE class Foo below. (I went through the same class earlier, with all methods in Foo being public - in case you've got a déjà vu...)

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:

When I try to run the test below, I get a NPE from PowerMock:

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

如果将存根设置为PowerMockito.spy(foo),则会得到一个IllegalArgumentException: argument type mismatch at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:2014). (它在与NPE相同的行上冒泡.)

If I make the stub a PowerMockito.spy(foo), I get an IllegalArgumentException: argument type mismatch at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:2014) instead. (It's bubbling up on the same line as the NPE.)

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

I'm using Mockito-core 1.9.5, PowerMock 1.5.4 (module-junit4 and api-mockito) and JUnit 4.11.

我需要更改什么才能阻止引发异常?如何使该测试有效? (除了测试 我的课程是否有效,而不是如何 ... ;-))

What do I need to change to stop the exceptions from being thrown? How can I make this test work? (Other than testing that my class works, instead of how... ;-) )

推荐答案

设置期望值时,我们必须使用精确的参数匹配器.在你的情况下 Matchers.any(Xray.class),Matchers.any(Baz.class)

When setting the expectations, we have to use the exact argument matcher. In your case, it is Matchers.any(Xray.class), Matchers.any(Baz.class)

我如下修改了您的代码,并在测试方法的输出对象上添加了assert语句.

I have modified your code as below and also added assert statement on output object of your test method.

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

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

Observation : when calling verify methods, we have to pass stub object not actual object because we set expectations on stub object. As I added assert statements to test the method, you don't have to verify on the stub whether it is working properly or not.

已添加: 我在public& amp;中添加了sysout语句.私有"bar"方法,当我再次测试时,我看到未打印public bar方法的sysout语句. 这意味着上面的代码仅模拟了公共方法,而没有模拟私有方法.

ADDED: I added sysout statements in both public & private 'bar' methods and when I tested again, I see that sysout statement of public bar method is not printed. It means the above code mocked public method only but not private method.

为了模拟私有的"bar"方法,我尝试了另一种使用MemberMatcher.method的模拟方法,该方法非常有效.

To mock private 'bar' method, I tried with another way of mocking using MemberMatcher.method which worked perfectly.

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

测试方法也已通过.下面是具有sysout的foo方法.

Test method is also passed. Below are foo methods having sysouts.

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

这篇关于尝试对私有重载方法进行存根时,PowerMockito抛出NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆