Java 如何使用assertj执行键和值的深度匹配

Java 如何使用assertj执行键和值的深度匹配,java,assertj,Java,Assertj,假设我有一门课是这样的: public class Character { public Character(String name){ this.name = name; } private String name; public String getName() { return name; } } assertThat(characterAges) .hasKey(key.extracting("name").contai

假设我有一门课是这样的:

public class Character {
   public Character(String name){
      this.name = name;
   }
   private String name;
   public String getName() { return name; }
}
assertThat(characterAges)
               .hasKey(key.extracting("name").contains("Frodo")
               .hasValue(34);
assertThat(characterAges).contains(entry("Frodo", 34), ...);
后来,一张地图

Map<Character, Integer> characterAges = new HashMap<Character, Integer>();
characterAges.put(new Character("Frodo"), 34);
我知道我能做到:

assertThat(characterAges.keySet())
               .extracting("name")
               .contains("Frodo");
但后来我就不那么流利了。我真正想要的是这样的:

public class Character {
   public Character(String name){
      this.name = name;
   }
   private String name;
   public String getName() { return name; }
}
assertThat(characterAges)
               .hasKey(key.extracting("name").contains("Frodo")
               .hasValue(34);
assertThat(characterAges).contains(entry("Frodo", 34), ...);
或者更好,这样我可以确保我的键和值匹配:

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

这样做可能吗?

没有简单的解决办法。一种方法是为角色映射实现一个。下面是此问题的一个简单自定义断言示例:

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

}
请注意,您必须为每个自定义数据结构编写自己的断言。对于
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"
    );
assertThat(characterAges).匹配(
(地图t)
->t.entrySet().stream().anyMatch((Map.Entry t1)
->“Frodo”.equals(t1.getKey().getName())&&34==t1.getValue()),
“是佛罗多,34岁”
);

您也可以这样做:

public class Character {
   public Character(String name){
      this.name = name;
   }
   private String name;
   public String getName() { return name; }
}
assertThat(characterAges)
               .hasKey(key.extracting("name").contains("Frodo")
               .hasValue(34);
assertThat(characterAges).contains(entry("Frodo", 34), ...);

请参见

如果您不想走自定义断言路线,并且可以在测试中访问SUT(测试中的系统)中的字符实例,则可以选择另一个选项

在SUT中:

Character frodo = new Character("Frodo");
characterAges.put(frodo, 34);
在测试中

MapEntry frodoAge34 = MapEntry.entry(frodo, 34);
assertThat(characterAges).contains(frodoAge34);

我不确定介绍的日期/版本,但是现在
MapAssert
中有很多断言。发件人:

包含(映射条目…条目) -验证实际映射是否按任何顺序包含给定的条目

containsAnyOf(映射条目…条目) -验证实际映射是否至少包含一个给定条目

containsExactly(映射条目…条目) -按顺序验证实际映射是否只包含给定的条目而不包含其他内容

集装箱箱(钥匙…钥匙) -验证实际映射是否包含给定的键

仅包含(映射条目…条目) -验证实际映射是否只包含给定的条目,而不包含其他任何顺序的条目

containsOnlyKeys(键…键) -验证实际映射是否只包含给定的键,而不包含其他任何顺序的键

包含值(值…值) -验证实际映射是否包含给定值

doesNotContain(映射条目…条目) -验证实际映射是否不包含给定的条目

不包含链接(键…键) -验证实际映射是否不包含任何给定键

提取(函数,对象>…提取程序) -使用给定的函数将值从被测对象提取到列表中,此新列表将成为被测对象


例如,
containsExactly()
应该可以做到这一点。

.entrySet()
.extracting()
一起使用怎么样

以下方法适用于您:

  • containsExactEntriesof验证实际地图是否仅包含给定地图的条目,而不包含其他任何内容,顺序为。这应该与TreeMap一起使用。HashMap不会保证顺序,您的测试将随机失败

  • containsExactlyInOrderEntriesOf验证实际地图是否只包含给定的条目,而不包含其他任何顺序的条目。这将适用于HashMap

  • import java.util.Map;
    导入org.assertj.core.api.Assertions;
    导入org.junit.jupiter.api.Test;
    公共类TestMapAssertions{
    @试验
    public void testCreateMap(){
    //召唤
    Map actual=ClassUnderTest.createMap();
    //断言
    Assertions.assertThat(实际)。包含(
    地图(“键1”、“值1”、“键2”、“值2”)
    );
    }
    测试中的公共静态类{
    公共静态映射createMap(){
    返回地图(“键1”、“值1”、“键2”、“值2”);
    }
    }
    }
    
    这似乎很接近,但在我的问题中,关键是字符,而不是字符串。我如何断言它是一个名为“Frodo”的字符?因为3.6.0有一个方法“HasEntrySuccessing()”正好解决了这个问题。看见