如何使用 assertj 执行更深入的键和值匹配

2022-09-02 13:24:08

假设我有一个这样的类:

public class Character {
   public Character(String name){
      this.name = name;
   }
   private String name;
   public String getName() { return name; }
}

后来,地图

Map<Character, Integer> characterAges = new HashMap<Character, Integer>();
characterAges.put(new Character("Frodo"), 34);

使用assertj,测试角色Ages是否包含“Frodo”角色的最佳方法是什么?对于年龄,我可以做:

assertThat(characterAges).hasValue(34);

我知道我可以做到:

assertThat(characterAges.keySet())
               .extracting("name")
               .contains("Frodo");

但后来我失去了流利度。我真正想要的是这样的:

assertThat(characterAges)
               .hasKey(key.extracting("name").contains("Frodo")
               .hasValue(34);

或者更好的是,这样我就可以确保我的键和值匹配:

assertThat(characterAges)
               .hasEntry(key.extracting("name").contains("Frodo"), 34);

这样的事情可能吗?


答案 1

对此没有简单的解决方案。一种方法是为字符映射实现自定义断言。下面是此问题的简单自定义断言示例:

public class CharacterMapAssert extends AbstractMapAssert<MapAssert<Character, Integer>, Map<Character, Integer>, Character, Integer> {

    public CharacterMapAssert(Map<Character, Integer> actual) {
        super(actual, CharacterMapAssert.class);
    }

    public static CharacterMapAssert assertThat(Map<Character, Integer> actual) {
        return new CharacterMapAssert(actual);
    }

    public CharacterMapAssert hasNameWithAge(String name, int age) {
        isNotNull();

        for (Map.Entry<Character, Integer> entrySet : actual.entrySet()) {
            if (entrySet.getKey().getName().contains(name) && (int) entrySet.getValue() == age) {
                return this;
            }
        }

        String msg = String.format("entry with name %s and age %s does not exist", name, age);
        throw new AssertionError(msg);
    }

}

在测试用例中:

assertThat(characterAges).hasNameWithAge("Frodo", 34);

请注意,每个自定义数据结构都必须编写自己的断言。对于您的类,您可以使用 AssertJ 断言生成器生成断言Character


更新 Java 8

与Java 8还可以使用Lambda表达式

    assertThat(characterAges).matches(
            (Map<Character, Integer> t)
            -> t.entrySet().stream().anyMatch((Map.Entry<Character, Integer> t1)
                    -> "Frodo".equals(t1.getKey().getName()) && 34 == t1.getValue()),
            "is Frodo and 34 years old"
    );

答案 2

您也可以执行类似如下操作:

assertThat(characterAges).contains(entry("Frodo", 34), ...);

查看 https://github.com/joel-costigliola/assertj-core/wiki/New-and-noteworthy#new-map-assertions


推荐