Say I have a class like this:
public class Character {
public Character(String name){
this.name = name;
}
private String name;
public String getName() { return name; }
}
And later, a Map
Map<Character, Integer> characterAges = new HashMap<Character, Integer>();
characterAges.put(new Character("Frodo"), 34);
Using assertj, what is the best way to test that characterAges includes the "Frodo" character? For the age, I can do:
assertThat(characterAges).hasValue(34);
And I know I could do:
assertThat(characterAges.keySet())
.extracting("name")
.contains("Frodo");
But then I lose my fluency. What I really want it something like this:
assertThat(characterAges)
.hasKey(key.extracting("name").contains("Frodo")
.hasValue(34);
Or even better, so that I can make sure my key and value match:
assertThat(characterAges)
.hasEntry(key.extracting("name").contains("Frodo"), 34);
Is something like this possible?
There is no easy solution for this. One way is to implement a custom Assertion for the character map. Here is a simple custom Assertion example for this problem:
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);
}
}
In the test case:
assertThat(characterAges).hasNameWithAge("Frodo", 34);
Be aware that you have for every custom data structure to write your own assertion. For you Character
class you can generate a assertion with the AssertJ assertions generator.
Update Java 8
With Java 8 can also the Lambda Expression used
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"
);
You can also do something like this:
assertThat(characterAges).contains(entry("Frodo", 34), ...);
See https://github.com/joel-costigliola/assertj-core/wiki/New-and-noteworthy#new-map-assertions
The following methods of AbstractMapAssert will work for you:
containsExactlyEntriesOf Verifies that the actual map contains only the entries of the given map and nothing else, in order. This should be used with TreeMap. HashMap will not guarantee order and your test will randomly fail.
containsExactlyInAnyOrderEntriesOf Verifies that the actual map contains only the given entries and nothing else, in any order. This will work with 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");
}
}
}
Since 3.6.0, you can use hasEntrySatisfying:
assertThat(characterAges)
.hasSize(1)
.hasEntrySatisfying(aKey, e ->
assertThat(e)
.isEqualTo(99.99)
);
In your case, if you cannot use the key for lookup you can use Condition-based hasEntrySatisfying (more verbose).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With