简体   繁体   English

fest和assert-j与自定义映射之间的细微差别

[英]Subtle difference between fest and assert-j with custom map

in the project where I am working it has been decided to stop using fest for test assertions, and instead use assertj. 在我正在工作的项目中,已经决定停止将fest用于测试断言,而改为使用assertj。 We are using Java 7 and we are moving from fest version 2.0M10 to assertj-core version 2.4.1. 我们正在使用Java 7,并且从fest版本2.0M10迁移到assertj-core版本2.4.1。 The code base is fairly big but the transition from fest to assertj has been smooth, basically changing import names and coping with renamed methods. 代码库相当大,但是从fest到assertj的过渡很顺畅,基本上可以更改导入名称并应对重命名的方法。 However, I noticed we were getting test failures in a particular test class after the transition (I should add we are using JUnit v4.12). 但是,我注意到在过渡之后,我们在特定的测试类中遇到了测试失败(我应该补充一点,我们正在使用JUnit v4.12)。 Below I show a small, self-contained testcase highlighting the issue: 下面,我显示了一个小而完整的测试用例,突出了这个问题:

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);
    }
}

I am sorry for such a long piece of code. 这么长的代码对不起。 As you can see from the the test result, there seems to be a difference between fest and assertj when one is using isEqualTo() on hashmaps, where one of the hashmaps is encapsulated in a class implementing the interface map. 从测试结果中可以看出,当在哈希表上使用isEqualTo()时,fest和assertj之间似乎有所不同,其中,哈希表之一封装在实现接口映射的类中。 My question is how to handle this? 我的问题是如何处理? I could flip the order in the assertion, ie having assertThat(b).isEqualTo(a) instead of having assertThat(a).isEqualTo(b). 我可以翻转断言中的顺序,即拥有assertThat(b).isEqualTo(a)而不是拥有assertThat(a).isEqualTo(b)。 But it feels little weird to me having to do such a flip one on particular assertion in a big test class with many assertions. 但这对我在具有许多断言的大型测试类中对特定断言进行这样的翻转感到很奇怪。 Is this difference between fest and assertj expected or unexpected? fest和assertj之间的差异是预期的还是意外的? Is the behavior expected from either (since both fail on one expression)? 这是预期的行为吗(因为两个表达式都失败)? How should I update the testcase, is there a better to do the equality check with the scenario in code above? 我应该如何更新测试用例,是否可以更好地对上述代码中的场景进行相等性检查? Thanks for reading this far and thanks for any advice! 感谢您阅读本文并感谢您的任何建议!

Well, the bug is in your code, and each library would spot the bug if you tested the contract of equals(), wich must be symmetric: A equals B iff B equals A. 好吧,该错误存在于您的代码中,并且如果您测试equals()的约定,那么每个库都会发现该错误,并且必须对称:A等于B且B等于A。

I would simply fix your code, and be happy to have discovered the bug thanks to the migration. 我将只修复您的代码,并很高兴由于迁移而发现了该错误。 I would also improve the tests and do 我也会改善测试并做

assertThat(a).isEqualTo(b);
assertThat(b).isEqualTo(a);

to make sure that the contract is fulfilled. 确保履行合同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM