Вопрос по powermock, java, overloading, private-members, powermockito – PowerMockito выдает исключение NullPointerException при попытке заглушить закрытый перегруженный метод

2

Я (все еще) пытаюсь проверить,bar(Alpha, Baz) называетсяbar(Xray, Baz) используя PowerMockito (какbar(Xray, Baz) являетсяprivate) - без фактического вызова позже, учитывая мой класс MCVEFoo ниже. (Я прошел через тот же классранеесо всеми методами в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;
        }
    }
}

Когда я пытаюсь запустить тест ниже, я получаю NPE от 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.)

Я использую ядро ​​Mockito 1.9.5, PowerMock 1.5.4 (module-junit4 и api-mockito) и JUnit 4.11.

Что мне нужно изменить, чтобы исключить выбросы исключений? Как я могу заставить этот тест работать? (Кроме кактестированиетот мой класс работает, а некак... ;-))

Ваш Ответ

1   ответ
2

гументов. В вашем случае это Matchers.any (Xray.class), Matchers.any (Baz.class)

Я изменил ваш код, как показано ниже, а также добавил утверждение assert для выходного объекта вашего тестового метода.

@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 для проверки метода, вам не нужно проверять заглушку, работает ли она правильно или нет.

ДОБАВЛЕНО: Я добавил операторы sysout в методы public и private 'bar', и при повторном тестировании я вижу, что оператор sysout метода public bar не печатается. Это означает, что в приведенном выше коде смоделирован только публичный метод, но не приватный метод.

Чтобы смоделировать приватный метод '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

Метод испытания также пройден. Ниже приведены методы foo, имеющие 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.verifyPrivate(stub, times(5)).invoke("bar", Matchers.any(Xray.class), Matchers.any(Baz.class)); оказывается, вы проверяете, как часто вы звонитеString res = stub.bar(alpha, baz); - это не похоже наFoo сам. Что имеет смысл, так какany() всегда возвращаетсяvoid насколько я знаю - поэтому PowerMock не имеет возможности проверить типы во время выполнения - и соответствуетbar(Alpha, Baz). Christian
Меняя его наMethod m = Whitebox.getMethod(Foo.class, Xray.class, Baz.class); PowerMockito.doReturn("ok").when(stub, m).withArguments(any(Xray.class), any(Baz.class)); заtimes(5) просто делает это терпеть неудачу сWanted but not invoked: foo.bar(<any>, <any>); -> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) Actually, there were zero interactions with this mock. Christian
@Christian, мой первый ответ не издевался над методом приватных баров, вместо этого он издевался над методом публичных баров, я исправил метод теста с помощью MemberMatcher.method, посмотрите подробное объяснение в моем обновленном ответе. kswaughs

Похожие вопросы