我有需要模拟 HashMap 类的测试用例,但 JMockit 在模拟它时似乎遇到了困难。 以下代码在 Expectations block 中触发 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");
}
如果我用任何 POJO 替换 HashMap,JMockIt 可以模拟它并且测试会成功。 事实上,JMockit 似乎无法从 Java 集合框架中模拟任何具体类(也无法模拟任何具体类的派生类)。
下面的测试用例说明了这个问题:
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
}
我会在使用 JMockit 时产生误解吗?
感谢您的帮助。
最佳答案
由于 JMockit 中的错误,mock 参数为 null,如果它们碰巧被模拟,则会影响某些广泛使用的 JRE 类(包括 ArrayList、HashMap 和其他一些)。
这个 bug 可以修复,但这里真正的问题是是否应该首先允许模拟这些类。在我看来,他们不应该这样做,因为几乎可以肯定没有合法的用例。
在问题中暴露的情况下,测试应该:
a) 通过公共(public) getter 或其他方法的返回值验证某些内部集合/映射的状态;
b) 或者,作为最后的手段,使用反射来获取对内部状态的访问(mockit.Deencapsulation
在这里可以提供帮助)。
同样的规则应该适用于 AbstractCollection
、HashMap
等的子类,因为它们也只是数据持有者,不应该 mock 。更一般地说,java.util.*
接口(interface)方法不应该是可模拟的(有少数异常(exception))。在未来的版本中,JMockit 将在尝试使用 Expectations API 模拟此类方法时抛出描述性异常。
归根结底,无论是因为该工具无法正确模拟它,还是它不会选择模拟它,如果不能编写此类测试,对用户来说是最好的。 “值对象”类和集合/映射根本不应该被 mock ;总是有更好的方法来编写测试。
关于java - JMockit 无法模拟来自 JRE 的具体集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28154108/