带有自定义映射的 fest 和 assert-j 之间的细微差别
Subtle difference between fest and assert-j with custom map
在我工作的项目中,已决定停止使用 fest 进行测试断言,而是使用 assertj。我们正在使用 Java 7,我们正在从 fest 版本 2.0M10 迁移到 assertj-core 版本 2.4.1。代码库相当大,但从 fest 到 assertj 的过渡很顺利,基本上更改了导入名称并处理重命名的方法。
但是,我注意到我们在转换后的特定测试 class 中遇到了测试失败(我应该补充说我们使用的是 JUnit v4.12)。下面我展示了一个小的、独立的测试用例,突出了这个问题:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
class MyMap implements Map<String, Object> {
private Map<String, Object> theMap = new HashMap<>();
@Override
public int size() {
return theMap.size();
}
@Override
public boolean isEmpty() {
return theMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return theMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return theMap.containsValue(value);
}
@Override
public Object get(Object key) {
return theMap.get(key);
}
@Override
public Object put(String key, Object value) {
return theMap.put(key, value);
}
@Override
public Object remove(Object key) {
return theMap.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends Object> m) {
theMap.putAll(m);
}
@Override
public void clear() {
theMap.clear();
}
@Override
public Set<String> keySet() {
return theMap.keySet();
}
@Override
public Collection<Object> values() {
return theMap.values();
}
@Override
public Set<java.util.Map.Entry<String, Object>> entrySet() {
return theMap.entrySet();
}
}
public class TestMapComparison {
private Map<String, Object> m1 = new HashMap<>();
private MyMap m2 = new MyMap();
@Before
public void before() {
m1.put("a", "b");
m2.put("a", "b");
}
// Fails with:
// java.lang.AssertionError:
// expected: <'{'a'='b'} (MyMap@6f5fc7ad)'>
// but was: <'{'a'='b'} (HashMap@3)'>
@Test
public void test1_Fest_m1_isEqualTo_m2() {
org.fest.assertions.api.Assertions.assertThat(m1).isEqualTo(m2);
}
@Test // Pass
public void test2_AssertJ_m1_isEqualTo_m2() {
org.assertj.core.api.Assertions.assertThat(m1).isEqualTo(m2);
}
@Test // Pass
public void test3_Fest_m2_isEqualTo_m1() {
org.fest.assertions.api.Assertions.assertThat(m2).isEqualTo(m1);
}
// Fails with:
// java.lang.AssertionError:
// Expecting: <"{"a"="b"} (MyMap@5aedacd2)">
// to be equal to:
// <"{"a"="b"} (HashMap@3)"> but was not.
@Test
public void test4_AssertJ_m2_isEqualTo_m1() {
org.assertj.core.api.Assertions.assertThat(m2).isEqualTo(m1);
}
}
很抱歉这么长的代码。正如您从测试结果中看到的那样,当在 hashmaps 上使用 isEqualTo() 时,fest 和 assertj 之间似乎存在差异,其中一个 hashmaps 封装在实现接口映射的 class 中。
我的问题是如何处理这个?我可以翻转断言中的顺序,即使用 assertThat(b).isEqualTo(a) 而不是 assertThat(a).isEqualTo(b)。但是我觉得在一个有很多断言的大测试 class 中不得不对特定断言做这样的翻转有点奇怪。 fest 和 assertj 之间的这种差异是预期的还是意外的?行为是否符合预期(因为两者都在一个表达式上失败)?我应该如何更新测试用例,是否可以更好地与上面代码中的场景进行相等性检查?感谢您阅读到这里并感谢您的任何建议!
好吧,这个错误在你的代码中,如果你测试了 equals() 的契约,每个库都会发现这个错误,它必须是对称的:A 等于 B 当且仅当 B 等于 A。
我会简单地修复您的代码,并且很高兴通过迁移发现了错误。我也会改进测试并做
assertThat(a).isEqualTo(b);
assertThat(b).isEqualTo(a);
确保合同得到履行。
在我工作的项目中,已决定停止使用 fest 进行测试断言,而是使用 assertj。我们正在使用 Java 7,我们正在从 fest 版本 2.0M10 迁移到 assertj-core 版本 2.4.1。代码库相当大,但从 fest 到 assertj 的过渡很顺利,基本上更改了导入名称并处理重命名的方法。 但是,我注意到我们在转换后的特定测试 class 中遇到了测试失败(我应该补充说我们使用的是 JUnit v4.12)。下面我展示了一个小的、独立的测试用例,突出了这个问题:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
class MyMap implements Map<String, Object> {
private Map<String, Object> theMap = new HashMap<>();
@Override
public int size() {
return theMap.size();
}
@Override
public boolean isEmpty() {
return theMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return theMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return theMap.containsValue(value);
}
@Override
public Object get(Object key) {
return theMap.get(key);
}
@Override
public Object put(String key, Object value) {
return theMap.put(key, value);
}
@Override
public Object remove(Object key) {
return theMap.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends Object> m) {
theMap.putAll(m);
}
@Override
public void clear() {
theMap.clear();
}
@Override
public Set<String> keySet() {
return theMap.keySet();
}
@Override
public Collection<Object> values() {
return theMap.values();
}
@Override
public Set<java.util.Map.Entry<String, Object>> entrySet() {
return theMap.entrySet();
}
}
public class TestMapComparison {
private Map<String, Object> m1 = new HashMap<>();
private MyMap m2 = new MyMap();
@Before
public void before() {
m1.put("a", "b");
m2.put("a", "b");
}
// Fails with:
// java.lang.AssertionError:
// expected: <'{'a'='b'} (MyMap@6f5fc7ad)'>
// but was: <'{'a'='b'} (HashMap@3)'>
@Test
public void test1_Fest_m1_isEqualTo_m2() {
org.fest.assertions.api.Assertions.assertThat(m1).isEqualTo(m2);
}
@Test // Pass
public void test2_AssertJ_m1_isEqualTo_m2() {
org.assertj.core.api.Assertions.assertThat(m1).isEqualTo(m2);
}
@Test // Pass
public void test3_Fest_m2_isEqualTo_m1() {
org.fest.assertions.api.Assertions.assertThat(m2).isEqualTo(m1);
}
// Fails with:
// java.lang.AssertionError:
// Expecting: <"{"a"="b"} (MyMap@5aedacd2)">
// to be equal to:
// <"{"a"="b"} (HashMap@3)"> but was not.
@Test
public void test4_AssertJ_m2_isEqualTo_m1() {
org.assertj.core.api.Assertions.assertThat(m2).isEqualTo(m1);
}
}
很抱歉这么长的代码。正如您从测试结果中看到的那样,当在 hashmaps 上使用 isEqualTo() 时,fest 和 assertj 之间似乎存在差异,其中一个 hashmaps 封装在实现接口映射的 class 中。 我的问题是如何处理这个?我可以翻转断言中的顺序,即使用 assertThat(b).isEqualTo(a) 而不是 assertThat(a).isEqualTo(b)。但是我觉得在一个有很多断言的大测试 class 中不得不对特定断言做这样的翻转有点奇怪。 fest 和 assertj 之间的这种差异是预期的还是意外的?行为是否符合预期(因为两者都在一个表达式上失败)?我应该如何更新测试用例,是否可以更好地与上面代码中的场景进行相等性检查?感谢您阅读到这里并感谢您的任何建议!
好吧,这个错误在你的代码中,如果你测试了 equals() 的契约,每个库都会发现这个错误,它必须是对称的:A 等于 B 当且仅当 B 等于 A。
我会简单地修复您的代码,并且很高兴通过迁移发现了错误。我也会改进测试并做
assertThat(a).isEqualTo(b);
assertThat(b).isEqualTo(a);
确保合同得到履行。