将jmockit期望与匹配器和原始类型一起使用

时间:2020-03-06 14:19:27  来源:igfitidea点击:

我正在使用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,而是内部匹配器中的实际参数值)。