18

假设我有这样的课程:

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,测试 characterAges 是否包含“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);

这样的事情可能吗?

4

7 回答 7

5

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

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

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


更新 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"
    );
于 2015-02-01T10:24:40.137 回答
5

你也可以这样做:

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

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

于 2015-10-01T15:06:49.383 回答
3

AbstractMapAssert的以下方法将为您工作:

  1. containsExactlyEntriesOf验证实际地图是否仅包含给定地图的条目,而没有其他内容,按顺序排列。这应该与 TreeMap 一起使用。HashMap 不保证顺序,您的测试将随机失败。

  2. containsExactlyInAnyOrderEntriesOf验证实际地图是否仅包含给定的条目,不包含其他任何顺序。这将适用于 HashMap。

import java.util.Map;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

public class TestMapAssertions {

    @Test
    public void testCreateMap() {
        //Call
        Map<String, String> actual = ClassUnderTest.createMap();

        //Assert
        Assertions.assertThat(actual).containsExactlyInAnyOrderEntriesOf(
                Map.of("Key1", "Value1", "Key2", "Value2")
        );
    }

    public static class ClassUnderTest {

        public static Map<String, String> createMap() {
            return Map.of("Key1", "Value1", "Key2", "Value2");
        }
    }
}
于 2021-01-22T21:42:35.580 回答
2

我不确定介绍的日期/版本,但现在有很多断言MapAssert。来自http://joel-costigliola.github.io/assertj/core-8/api/org/assertj/core/api/MapAssert.html

contains(Map.Entry... entries) - 验证实际地图是否以任何顺序包含给定条目。

containsAnyOf(Map.Entry... entries) - 验证实际地图是否包含至少一个给定条目。

containsExactly(Map.Entry... entries) - 验证实际地图是否按顺序仅包含给定的条目而没有其他内容。

containsKeys(KEY... keys) - 验证实际地图是否包含给定的键。

containsOnly(Map.Entry... entries) - 验证实际地图是否仅包含给定的条目,不包含其他任何顺序。

containsOnlyKeys(KEY... keys) - 验证实际地图是否仅包含给定的键,不包含其他任何顺序。

containsValues(VALUE... values) - 验证实际地图是否包含给定值。

doesNotContain(Map.Entry... entries) - 验证实际地图不包含给定条目。

doesNotContainKeys(KEY... keys) - 验证实际地图不包含任何给定的键。

extracting(Function,Object>... extractors) - 使用给定的函数将被测对象的值提取到一个列表中,这个新列表成为被测对象。

对于你的例子,containsExactly()应该做的伎俩。

于 2018-11-21T17:01:57.780 回答
0

从 3.6.0 开始,您可以使用hasEntrySatisfying

 assertThat(characterAges)
            .hasSize(1)
            .hasEntrySatisfying(aKey, e ->
                    assertThat(e)
                            .isEqualTo(99.99)
            );

在您的情况下,如果您不能使用键进行查找,您可以使用基于条件的hasEntrySatisfying(更详细)。

于 2021-06-24T06:47:06.873 回答
0

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

在 SUT 中:

Character frodo = new Character("Frodo");
characterAges.put(frodo, 34);

并且在测试中

MapEntry frodoAge34 = MapEntry.entry(frodo, 34);
assertThat(characterAges).contains(frodoAge34);
于 2018-09-14T10:25:37.533 回答
0

使用.entrySet()with怎么样.extracting()

assertThat(characterAges.entrySet())
 .extracting(
       entry -> entry.getKey().getName(), 
       Map.Entry::getValue)
 .contains(tuple("Frodo", 34));

于 2019-04-30T13:06:36.267 回答