Powermock: издевательский метод все еще вызывается

Прежде всего, знайте, что я искал SO, прежде чем задавать этот вопрос, но не смог найти удовлетворительного ответа.

Я использую JUnit4 и Powermock 1.5.5 (с mockito 1.9.5)

Моя проблема заключается в следующем: в моих модульных тестах мне нужно смоделировать статический метод в классе, который я не могу изменить. Я хочу издеваться только над одним методом, а не над всем классом, поэтому я пошел на шпиона.

Вот что у меня есть до сих пор:

[...]
import static org.mockito.Matchers.*;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(JUnitParamsRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext-test.xml"},
    loader=MockWebApplicationContextLoader.class)
@MockWebApplication(name="my-app")
@PrepareForTest(value = {
    Role.class
})
public class MyTest {

    @Rule
    public PowerMockRule powerMockRule = new PowerMockRule();

    @Before
    public void setUp() throws Exception {
        initSpring();
        mockRoleServices();
    }

    private void mockRoleServices() throws Exception {
        spy(Role.class);
        RoleAnswer roleAnswer = new RoleAnswer(RoleEnum.ADMIN);
        when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
            .then(roleAnswer);
    }

    private class RoleAnswer implements Answer<Boolean> {

        private RoleEnum roleEnum;

        private RoleAnswer(RoleEnum roleEnum) {
            this.roleEnum = roleEnum;
        }

        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            return getRenderRequest().getUserRole() != null &&
                    getRenderRequest().getUserRole().equals(roleEnum);
        }
    }
}

Вот в чем проблема: метод Role.hasAdministratorRole() вызывается вместо того, чтобы над ним издеваться

Вот что я пробовал до сих пор:

  • Использование mockStatic(Role.class) вместо метода spy(). Как и ожидалось, все методы имитируются, поэтому я получаю NPE до вызова Role.hasAdministratorRole()
  • Делая что-то вроде doAnswer(...).when(...). Я получаю ошибку времени выполнения, когда powermock сообщает мне, что мой макет не завершен (что на самом деле подтверждает, что что-то не так либо с моим кодом, либо с самой библиотекой)
  • Попытка объявить метод по его имени, а не вызывать его напрямую: when(Role.class, "hasAdministratorRole", long.class, long.class, long.class). То же поведение
  • Куча других вещей, которые я уже не помню.

Ваша помощь будет принята с благодарностью. Спасибо !

EDIT: благодаря ответу SrikanthLingala я смог точно определить проблему.

Это не сработало:

when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
    .thenAnswer(roleAnswer);

но это сделало:

doAnswer(roleAnswer).when(Role.class, "hasSiteAdministratorRole",
    anyLong(), anyLong(), anyLong());

Итак, переключение между when() и answer() сработало.


person Alexandre FILLATRE    schedule 18.06.2014    source источник
comment
Кроме того, я заметил, что класс, который я пытаюсь смоделировать, находится в банке в пути к классам (то есть не непосредственно в пути к классам). Может это актуально?   -  person Alexandre FILLATRE    schedule 18.06.2014
comment
Может быть, это потому, что вы не запускаете тест с помощью PowerMockRunner?   -  person Bevor    schedule 18.06.2014
comment
Другие макеты работают, потому что я использую PowerMockRule. Но в любом случае, я проверил это, и я получил точно такой же результат :(   -  person Alexandre FILLATRE    schedule 18.06.2014


Ответы (2)


Поскольку у меня нет всех ваших реализаций, я настроил несколько фиктивных реализаций и сделал настройку, аналогичную вашей. Приведенный ниже код отлично работает для меня.

import static junit.framework.Assert.assertTrue;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(value = {
    Role.class
})
public class RoleTest {

    @Test
    public void mockRoleServices() throws Exception {
        PowerMockito.spy(Role.class);
        PowerMockito.doAnswer(new RoleAnswer(RoleEnum.ADMIN)).when(Role.class, "hasAdministratorRole", Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());

        Role.printOut();

        assertTrue(Role.hasAdministratorRole(1, 1, 1));
    }

    private class RoleAnswer implements Answer<Boolean> {

        private RoleEnum roleEnum;

        private RoleAnswer(RoleEnum roleEnum) {
            this.roleEnum = roleEnum;
        }

        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            return true;
        }
    }
}

Класс фиктивной роли:

public class Role {

    public static Boolean hasAdministratorRole(long a, long b, long c) {
        System.out.println("Inside hasAdministratorRole");
        return a + b + c < 0;
    }

    public static void printOut() {
        System.out.println("Inside Printout");
    }

}

Мой тестовый пример не выводит Inside hasAdministratorRole, а выводит Inside Printout

Надеюсь это поможет

person Srikanth Reddy Lingala    schedule 18.06.2014
comment
Большое спасибо, что нашли время, чтобы протестировать его. Мне удалось заставить его работать с классами непосредственно в моем пути к классам (т.е. не в банке). Не могли бы вы попробовать поместить свои фиктивные классы в банку и повторно протестировать их? Я начинаю думать, что проблема в этом. - person Alexandre FILLATRE; 18.06.2014
comment
У меня хорошо работает даже из баночки. - person Srikanth Reddy Lingala; 18.06.2014
comment
Спасибо за ваш ответ, я смог заставить его работать. Я отредактировал свой вопрос, чтобы добавить ответ, но я действительно не понимаю, почему это работает. У вас есть подсказка? Еще раз спасибо за вашу драгоценную помощь - person Alexandre FILLATRE; 18.06.2014

Рад, что вы решили свою проблему, это просто предупреждение для всех, у кого есть аналогичная проблема.

Настройка проекта:

  • Пауэрмак 1.5.5
  • Мокито 1.9.5
  • ТестНГ 6.8.8

Powermock не учитывает моки/шпионы, созданные в методе, аннотированном с помощью @BeforeTest.

E.g.:

@BeforeTest
public void setup(){
    testee = mock(AClass.class);
}

Он отбрасывается, а затем входит в издевательский метод вместо того, чтобы возвращать ожидаемый результат ИЛИ выбрасывать всевозможные странные исключения. При переходе на общий метод тестирования он вдруг начинает работать:

@Test
public void test(){
    AClass testee = mock(AClass.class);
    ....
}

Возможно, это ошибка.

person Amio.io    schedule 25.06.2014
comment
Создана проблема: code.google.com/p/powermock /проблемы/ - person Amio.io; 26.06.2014