-
Notifications
You must be signed in to change notification settings - Fork 69
Tips and tricks
Here's some tips we are using to make writing tests easier and more elegant.
Please share your tips with us, this page can be edited by everybody !
- Exception assertion best practices
- Assertions on extracted properties of an iterable/array
- Using a custom comparison strategy in assertions
- filtering a group of objects before making assertions
TODO ...
When you are persisting objects, your persistent objects usually have ids. When writing a DAO/repository tests querying datastore, you only want to check that the returned objects have the expected ids.
You would write something like :
List<TolkienCharacter> fellowshipOfTheRing = tolkienDao.findHeroes(); // frodo, sam, aragorn ...
// extract the ids ...
List<Long> ids = new ArrayList<Long>();
for (TolkienCharacter tolkienCharacter : fellowshipOfTheRing) {
ids.add(tolkienCharacter.hashCode());
}
// ... and finally assert something
assertThat(ids).contains(1L, 2L, 3L);
It is too much work to have to extract ids, so we have made this scenario much easier by taking care for you of extracting the properties, see below :
// no more manual ids extraction !
assertThat(extractProperty("id", Long.class).from(fellowshipOfTheRing)).contains(1L, 2L, 3L);
// to be more type safe, you can define the property type with extractProperty second parameter
assertThat(extractProperty("id", Long.class).from(fellowshipOfTheRing)).contains(1L, 2L, 3L);
You can even extract nested properties using the dot notation, for example :
assertThat(extractProperty("race.name").from(fellowshipOfTheRing)).contains("Hobbit", "Elf")
See more examples in test collection_assertions_on_extracted_property_values_example from fest-examples project.
Sometime you want to compare objects with another strategy than equals
method, this is possible in Fest thanks to two methods :
-
usingComparator(Comparator)
: concerns object under assertion -
usingElementComparator(Comparator)
: concerns elements of iterable/array under assertion
usingComparator(Comparator) example :
// frodo and sam are instances of Character with Hobbit race (obviously :), they are not equal ...
assertThat(frodo).isNotEqualTo(sam);
// ... but if we compare race only, they are (raceComparator implements Comparator<Character>)
assertThat(frodo).usingComparator(raceComparator).isEqualTo(sam);
usingElementComparator(Comparator) example :
// standard comparison : the fellowshipOfTheRing includes Gandalf but not Sauron (believe me) ...
assertThat(fellowshipOfTheRing).contains(gandalf).doesNotContain(sauron);
// ... but if we compare race only, Sauron is in fellowshipOfTheRing (he's a Maia like Gandalf)
assertThat(fellowshipOfTheRing).usingElementComparator(raceComparator).contains(sauron);
Filtering can be done on arrays or iterables, filters criteria are expressed by :
- a Condition
- some operation on property of array/iterable elements
Let's see both options on some examples taken from FilterExamples from fest-examples project.
Filtering on extracted properties values
// with(property).equalsTo(someValue) works by instrospection on specified property
assertThat(filter(fellowshipOfTheRing).with("race").equalsTo(HOBBIT).get())
.containsOnly(sam, frodo, pippin, merry);
// same thing - shorter way
assertThat(filter(fellowshipOfTheRing).with("race", HOBBIT).get())
.containsOnly(sam, frodo, pippin, merry);
// nested property are supported
assertThat(filter(fellowshipOfTheRing).with("race.name").equalsTo("Man").get())
.containsOnly(aragorn, boromir);
// you can apply different comparison
assertThat(filter(fellowshipOfTheRing).with("race").notIn(HOBBIT, MAN).get())
.containsOnly(gandalf, gimli, legolas);
assertThat(filter(fellowshipOfTheRing).with("race").in(MAIA, MAN).get())
.containsOnly(gandalf, boromir, aragorn);
assertThat(filter(fellowshipOfTheRing).with("race").notEqualsTo(HOBBIT).get())
.contains(gandalf, boromir, gimli,aragorn, legolas);
// you can chain multiple filter criteria
assertThat(filter(fellowshipOfTheRing).with("race").equalsTo(MAN)
.and("name").notEqualsTo("Boromir").get())
.contains(aragorn);
}
Filtering with Condition
Two methods are available : being(Condition)
and having(Condition)
, they do the same job - pick the one that makes your code the more readable !
// having(condition) example
Condition<Player> mvpStats= new Condition<Player>() {
@Override
public boolean matches(Player player) {
return player.pointsPerGame() > 20 && (player.assistsPerGame() >= 8 || player.reboundsPerGame() >= 8);
}
};
assertThat(filter(players).having(mvpStats).get()).containsOnly(rose, james);
// being(condition) example : same condition can be applied but is renamed to be more readable
Condition<Player> potentialMvp= mvpStats;
assertThat(filter(players).being(potentialMvp).get()).containsOnly(rose, james);