将jmockit期望与匹配器和原始类型一起使用
我正在使用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"; } } } } /******************************************************/
包含对invokeReturning(...)的调用的行将引发NullPointerException。
如果我将此呼叫更改为不使用匹配器,如下所示:
invokeReturning(c.getFoo(false), "bas");
它工作正常。这对我没有好处,因为在我的真实代码中,我实际上在模拟多参数方法,并且需要在另一个参数上使用匹配器。在这种情况下,Expectations类要求所有参数都使用匹配器。
我很确定这是一个错误,或者可能无法将Matchers与原始类型一起使用(这会让我很难过)。有没有人遇到过这个问题,并且知道如何解决这个问题?
解决方案
问题是Expectation用法的组合,而Matchers不支持基本类型。
Matchers代码依赖于Generic,而Generic基本不支持基本类型。通常,Matchers的使用更多是为了匹配值;使用Java 5中的自动装箱/拆箱功能,这通常不是问题。
但是JMockit的Expectation并未将其用于匹配值,而是将其用于某种类型的解析以确定方法调用签名类型。在这种情况下,Matchers将导致布尔类型,而方法是原始类型。正确地模拟它。
很抱歉,我无法告诉我们任何解决方法。也许有人可以帮忙。
所以问题似乎出在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的来源来自原始布尔值的反自动装箱。
我通过将invokeReturning(...)调用更改为:
invokeReturning(withEqual(false)), "bas");
我在这里不再使用匹配器,但是它足以满足我的需求。
我更改了JMockit(版本0.982),以便" with(is(false())")和其他类似变体现在可以按预期工作(它不再返回null,而是内部匹配器中的实际参数值)。