JMockit无法模拟JRE的具体集合

emg*_*mgr 4 java unit-testing jmockit

我有需要模拟HashMap类的测试用例,但看起来JMockit在模拟时遇到了困难.以下代码在Expectations块中触发NPE:

public class TestKO {

public class ClassUnderTest {

    private final Map<String, String> dependency;

    public ClassUnderTest() {
        this.dependency = new HashMap<String, String>();
    }

    public void register(final String key, final String value) {
        dependency.put(key, value);
    }
}

@Test
public void ko(@Mocked("put") final HashMap<String, String> dep) {
    new Expectations() {{
            dep.put("key", "value"); // dep is null => NullPointerException !
        }};
    final ClassUnderTest c = new ClassUnderTest();
    c.register("key", "value");
}
Run Code Online (Sandbox Code Playgroud)

}

如果我用任何POJO替换HashMap,JMockIt可以模拟它并且测试将成功.事实上,似乎JMockit不能从Java Collection Framework中模拟任何具体的类(也没有派生任何具体类的类).

以下测试用例显示此问题:

public class MyTests {

public static class POJO {
}

public static class MyMapExtendingConcreteCollection extends HashMap<String, String> {
}

public static class MyMapExtendingAbstractCollection extends AbstractMap<String, String> {

    @Override
    public Set<java.util.Map.Entry<String, String>> entrySet() {
        return null;
    }

}

@Test
public void strangeBehaviors(@Mocked POJO mockedPOJO, @Mocked HashMap<String, String> mockedMap,
        @Mocked ConcurrentHashMap<String, String> mockedConcurrentMap,
        @Mocked MyMapExtendingConcreteCollection mockedMyMapFromConcrete,
        @Mocked MyMapExtendingAbstractCollection mockedMyMapFromAbstract) {
    assertNotNull(mockedPOJO); // OK : not null
    assertNotNull(mockedMap); // FAIL: null !
    assertNotNull(mockedConcurrentMap); // OK : not null
    assertNotNull(mockedMyMapFromConcrete); // FAIL: null !
    assertNotNull(mockedMyMapFromAbstract); // OK: not null
}
Run Code Online (Sandbox Code Playgroud)

}

我会误解使用JMockit的东西吗?

谢谢你的帮助.

Rog*_*rio 6

由于JMockit中的错误,mock参数为null,如果碰巧被模拟,会影响某些广泛使用的JRE类(包括ArrayList,HashMap和其他一些类).

错误可以修复,但真正的问题是这些类是否应该被允许首先被嘲笑.在我看来,它们不应该,因为几乎肯定没有合法的用例.

在问题中暴露的案例中,测试应该是:a)通过公共getter验证某些内部集合/映射的状态或某些其他方法的返回值; b)或作为最后的手段,使用Reflection来获得对内部状态的访问(mockit.Deencapsulation可以在这里提供帮助).

同样的规则也应适用于子类的AbstractCollection,HashMap等等,他们也仅仅是数据持有人不应该被嘲笑.更一般地说,没有java.util.*接口方法应该是可模拟的(除了少数例外).在将来的版本中,JMockit将尝试使用Expectations API模拟此类方法的描述性异常.

最重要的是,无论是因为该工具无法正确模拟它,或者它不会通过选择来模拟它,如果无法编写这样的测试,最好是用户."价值对象"类和集合/地图不应该被嘲笑; 总有更好的方法来编写测试.