public class MyProperties {
private Map<String, Object> properties = new HashMap<String, Object>();
public void setProperty(String name, Object value) {
properties.put(name, value);
}
@SuppressWarnings("unchecked")
public <T> T getProperty(String name) {
return (T) properties.get(name);
}
}
@Test
public void test() {
MyProperties props1 = new MyProperties();
props1.setProperty("name", "John Smith");
MyProperties props2 = new MyProperties();
props2.setProperty("name", "John Smith");
assertEquals(props2.getProperty("name"), props1.getProperty("name"));
}
上面的单元测试在我的机器上传递但在我们的jenkins环境中失败并出现以下错误:
java.lang.String cannot be cast to [Ljava.lang.Object;
单元测试通过Eclipse和ant(eclipse 4.4 luna,ant 1.9.6,jdk_8_u60,Windows 7 64bit)在我的机器上传递但在我们的jenkins环境中失败(ant 1.9.6 jdk_8_u60,Ubuntu 12.04.4) 。它在其他几个环境中也失败了,并在其他几个环境中工作 - 没有明显的押韵或理由。
所以我有两个问题:
1)为什么Java选择重载
org.junit.Assert.assertEquals(Object[],Object[])
而不是org.junit.Assert.assertEquals(String,String)
或org.junit.Assert.assertEquals(Object,Object)
?2)为什么单元测试在某些环境中传递,而在其他环境中使用相同版本的java,ant和junit失败?
答案 0 :(得分:3)
关于2:
不同的行为很可能不是由运行时环境引起的,而是由用于编译类的编译器引起的。
Eclipse有自己的Java编译器,而Jenkins使用JDK的javac。
似乎是Eclipse 4.4。生成assertEquals
行的调用,允许成功的测试运行,而javac生成对org.junit.Assert.assertEquals(Object[],Object[])
的调用,然后测试失败。
这在Eclipse 4.5中不起作用,它将在编译时抱怨对已弃用的方法Assert.assertEquals(Object[],Object[])
的调用,并且在Eclipse 4.5中运行时测试也会失败。
您可以通过反编译Eclipse 4.4和javac(使用(javap -c
)生成的类来测试假设,并检查他们选择的Assert方法。
关于1:
Assert有两个assertEquals方法接受两个对象:
Assert.assertEquals(Object expected, Object actual);
Assert.assertEquals(Object[] expecteds, Object[] actuals);
根据JLS(15.12),在编译方法调用时,编译器必须从所有适用的方法中选择最具体的方法。在示例中,这是Assert.assertEquals(Object[] expecteds, Object[] actuals)
。
这可能会让人感到困惑,因为JUnit可能决定使用数组参数弃用该方法。