Использование ожиданий jmockit для сопоставлений и примитивных типов
-
01-07-2019 - |
Вопрос
Я использую jmockit для модульного тестирования (с TestNG), и у меня возникли проблемы с использованием класса Expectations для имитации метода, который принимает примитивный тип (логический) в качестве параметра, используя средство сопоставления.Вот пример кода, иллюстрирующий проблему.
/******************************************************/
import static org.hamcrest.Matchers.is;
import mockit.Expectations;
import org.testng.annotations.Test;
public class PrimitiveMatcherTest {
private MyClass obj;
@Test
public void testPrimitiveMatcher() {
new Expectations(true) {
MyClass c;
{
obj = c;
invokeReturning(c.getFoo(with(is(false))), "bas");
}
};
assert "bas".equals(obj.getFoo(false));
Expectations.assertSatisfied();
}
public static class MyClass {
public String getFoo(boolean arg) {
if (arg) {
return "foo";
} else {
return "bar";
}
}
}
}
/******************************************************/
Строка, содержащая вызов метода ignoreReturning(...), вызывает исключение NullPointerException.
Если я изменю этот вызов, чтобы не использовать сопоставитель, как в:
invokeReturning(c.getFoo(false), "bas");
это работает просто отлично.Для меня это бесполезно, потому что в моем реальном коде я фактически имитирую многопараметрический метод, и мне нужно использовать сопоставитель для другого аргумента.В этом случае класс Expectations требует, чтобы все аргументы используют сопоставитель.
Я почти уверен, что это ошибка, или, возможно, невозможно использовать Matchers с примитивными типами (это меня расстроило бы).Кто-нибудь сталкивался с этой проблемой и знает, как ее обойти?
Решение 2
Итак, проблема, похоже, в Expectations.with():
protected final <T> T with(Matcher<T> argumentMatcher)
{
argMatchers.add(argumentMatcher);
TypeVariable<?> typeVariable = argumentMatcher.getClass().getTypeParameters()[0];
return (T) Utilities.defaultValueForType(typeVariable.getClass());
}
Вызов typeVariable.getClass() не делает того, что ожидает автор, а вызов типа Utilities.defaultValueFor возвращает значение null.Деавтобоксирование обратно к примитивному логическому значению — вот откуда берется NPE.
Я исправил это, изменив вызов ignoreReturning(...) на:
invokeReturning(withEqual(false)), "bas");
Я больше не использую здесь сопоставление, но оно достаточно хорошо для того, что мне нужно.
Другие советы
проблема заключается в сочетании использования ожиданий и того, что Matchers не поддерживает примитивный тип.
Код Matchers основан на Generic, который в основном не поддерживает примитивные типы.Обычно Matchers используются больше для сопоставления значений;с функцией автоматической упаковки/распаковки в Java 5 это обычно не является проблемой.
Но ожидание JMockit не использует его для сопоставления значения, оно использует его для какого-то анализа, чтобы определить тип сигнатуры вызова метода... что в этом случае Matchers приведет к логическому типу, в то время как ваш метод является примитивным типом... поэтому он терпит неудачу чтобы посмеяться над этим как следует.
Мне жаль, что я не могу подсказать вам обходной путь для этой проблемы.Может быть, кто-то еще сможет помочь.
Я изменил JMockit (выпуск 0.982), так что «with(is(false))» и другие подобные варианты теперь работают должным образом (он больше не возвращает ноль, а фактическое значение аргумента внутри внутреннего сопоставителя).