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的东西吗?
谢谢你的帮助.
由于JMockit中的错误,mock参数为null,如果碰巧被模拟,会影响某些广泛使用的JRE类(包括ArrayList,HashMap和其他一些类).
错误可以修复,但真正的问题是这些类是否应该被允许首先被嘲笑.在我看来,它们不应该,因为几乎肯定没有合法的用例.
在问题中暴露的案例中,测试应该是:a)通过公共getter验证某些内部集合/映射的状态或某些其他方法的返回值; b)或作为最后的手段,使用Reflection来获得对内部状态的访问(mockit.Deencapsulation可以在这里提供帮助).
同样的规则也应适用于子类的AbstractCollection,HashMap等等,他们也仅仅是数据持有人不应该被嘲笑.更一般地说,没有java.util.*接口方法应该是可模拟的(除了少数例外).在将来的版本中,JMockit将尝试使用Expectations API模拟此类方法的描述性异常.
最重要的是,无论是因为该工具无法正确模拟它,或者它不会通过选择来模拟它,如果无法编写这样的测试,最好是用户."价值对象"类和集合/地图不应该被嘲笑; 总有更好的方法来编写测试.