#java #unit-testing #junit4 #powermock
#java #модульное тестирование #junit4 #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 amp;amp;
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)
. То же поведение - Куча других вещей, которые я больше не помню.
Ваша помощь будет высоко оценена. Спасибо!
РЕДАКТИРОВАТЬ: благодаря ответу Шрикантлингалы я смог точно определить проблему.
Это не сработало :
when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
.thenAnswer(roleAnswer);
но это сделало :
doAnswer(roleAnswer).when(Role.class, "hasSiteAdministratorRole",
anyLong(), anyLong(), anyLong());
Итак, переключение тогда when()
и answer()
сработало
Комментарии:
1. Кроме того, я отметил, что класс, который я пытаюсь издеваться, находится в jar в пути к классу (т.Е. Не Непосредственно в пути к классу). Может ли это иметь отношение к делу?
2. Может быть, это потому, что вы не запускаете тест с помощью PowerMockRunner?
3. Другие издевательства работают, потому что я использую PowerMockRule. Но в любом случае, я протестировал его, и я получил точно такой же результат: (
Ответ №1:
Поскольку у меня нет всех ваших реализаций, я настроил несколько фиктивных реализаций и сделал аналогичную настройку, подобную вашей. Приведенный ниже код отлично работает для меня.
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
Надеюсь, это поможет
Комментарии:
1. Большое спасибо, что нашли время для его тестирования. Я смог заставить его работать с классами непосредственно в моем пути к классам (т. Е. Не В jar). Не могли бы вы, пожалуйста, попытаться поместить свои фиктивные классы в jar и повторно протестировать их? Я начинаю думать, что проблема в этом.
2. У меня отлично работает даже из jar.
3. Спасибо за ваш ответ, я смог заставить его работать. Я отредактировал свой вопрос, чтобы добавить ответ, но я действительно не понимаю, почему это работает. У вас есть подсказка? Еще раз спасибо за вашу драгоценную помощь
Ответ №2:
Рад, что вы решили свою проблему, это просто предупреждение для всех остальных, имеющих аналогичную проблему.
Настройка проекта:
- Powermock 1.5.5
- Mockito 1.9.5
- TestNG 6.8.8
Powermock не учитывает макеты / шпионы, созданные в методе, аннотированном @BeforeTest
Например.:
@BeforeTest
public void setup(){
testee = mock(AClass.class);
}
Он отбрасывается, а затем вводит издевательский метод вместо того, чтобы возвращать ожидаемый результат ИЛИ выдавать всевозможные странные исключения. При переходе к общему методу тестирования он внезапно начинает работать:
@Test
public void test(){
AClass testee = mock(AClass.class);
....
}
Возможно, это ошибка.
Комментарии:
1. Возникла проблема: code.google.com/p/powermock/issues /…