PowerMockito throws NullPointerException when trying to stub private overloaded method

后端 未结 1 1472
再見小時候
再見小時候 2021-01-23 03:03

I\'m (still) trying to check if bar(Alpha, Baz) called bar(Xray, Baz) using PowerMockito (as bar(Xray, Baz) is private) - wit

相关标签:
1条回答
  • 2021-01-23 03:48

    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)

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

    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.

    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.

    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
    

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题