Как выполнить более глубокое сопоставление ключей и значений с помощью assertj
Скажем, у меня есть класс вроде этого:
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);
Возможно ли подобное?
Ответы
Ответ 1
Для этого нет простого решения. Один из способов - реализовать custom Assertion для карты символов. Вот простой пример Assertion для этой проблемы:
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 assertions generator.
Обновить Java 8
В Java 8 также может использоваться выражение Lambda Expression
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
Ответ 3
Если вы не хотите идти по пути пользовательского утверждения и можете получить доступ к экземплярам символов в тестируемой системе (SUT) в тесте, другой вариант может быть
В ТУТ:
Character frodo = new Character("Frodo");
characterAges.put(frodo, 34);
И в тесте
MapEntry frodoAge34 = MapEntry.entry(frodo, 34);
assertThat(characterAges).contains(frodoAge34);
Ответ 4
Я не уверен насчет даты/версии введения, но в MapAssert
есть куча утверждений. От http://joel-costigliola.github.io/assertj/core-8/api/org/assertj/core/api/MapAssert.html:
содержит (Map.Entry... записи) - Проверяет, что фактическая карта содержит данные записи в любом порядке.
containsAnyOf (Map.Entry... records) - Проверяет, что фактическая карта содержит хотя бы одну из указанных записей.
containsExactly (Map.Entry... records) - Проверяет, что фактическая карта содержит только данные записи и ничего больше по порядку.
containsKeys (KEY... keys) - Проверяет, что фактическая карта содержит данные ключи.
containsOnly (Map.Entry... records) - Проверяет, что фактическая карта содержит только данные записи и ничего больше в любом порядке.
containsOnlyKeys (KEY... keys) - Проверяет, что фактическая карта содержит только данные ключи и ничего больше, в любом порядке.
containsValues (VALUE... values) - Проверяет, что фактическая карта содержит заданные значения.
didNotContain (Map.Entry... records) - Проверяет, что фактическая карта не содержит заданные записи.
didNotContainKeys (KEY... keys) - Проверяет, что фактическая карта не содержит ни одного из заданных ключей.
extracting (Function, Object>... extractors) - использует данные функции для извлечения значений из тестируемого объекта в список, причем этот новый список становится тестируемым объектом.
Для вашего примера, метод containsExactly()
.
Ответ 5
Как насчет использования .entrySet()
с .extracting()
?
assertThat(characterAges.entrySet())
.extracting(
entry -> entry.getKey().getName(),
Map.Entry::getValue)
.contains(tuple("Frodo", 34));