Tips and tricks - alexruiz/fest-assert-2.x GitHub Wiki
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 !
- IDE configuration to directly get
asserThat
in code completion - Exception assertions 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
- Using String assertions on the content of a file
The idea is to start typing asser and let code completion suggest you asserThat from Fest (and not the one from Hamcrest !).
- In Eclipse, go to : preferences > Java > Editor > Content assist > Favorites > New Type
- Enter : org.fest.assertions.api.Assertions
- You should see : org.fest.assertions.api.Assertions.* in a the list.
For Idea, I don't know, but I'm sure it's possible ;-)
The goal here is to assert that an exception has been thrown and that exception is the one expected.
- Put the code to should throw in a try-catch.
- Call a
fail
method immediately after the code that should throw an exception, so that if exception is not thrown, the test will fail. - Make assertions on the caught exception
Note that fail
method can statically imported from Assertions class
Example taken from FailUsageExamples in fest-example project :
import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.fail;
import static org.fest.assertions.api.Assertions.failBecauseExceptionWasNotThrown;
...
assertThat(fellowshipOfTheRing).hasSize(9);
// here's the typical pattern to use Fail :
try {
fellowshipOfTheRing.get(9); // argggl !
// we should not arrive here => use fail to expresses that
// if IndexOutOfBoundsException was not thrown, test would fail the specified message
fail("IndexOutOfBoundsException expected because fellowshipOfTheRing has only 9 elements");
} catch (IndexOutOfBoundsException e) {
assertThat(e).hasMessage("Index: 9, Size: 9");
}
// Warning : don't catch Throwable in catch clause as it would also catch AssertionError thrown by fail method
// another way to do the same thing
try {
fellowshipOfTheRing.get(9); // argggl !
// if IndexOutOfBoundsException was not thrown, test would fail with message :
// "Expected IndexOutOfBoundsException to be thrown"
failBecauseExceptionWasNotThrown(IndexOutOfBoundsException.class);
} catch (IndexOutOfBoundsException e) {
assertThat(e).hasMessage("Index: 9, Size: 9");
}
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 are taking care of that for you of extracting the properties, see below :
// no more manual ids extraction !
assertThat(extractProperty("id").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 method iterable_assertions_on_extracted_property_values_example
in IterableAssertionsExamples.java 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);
File assertions are rather poor when it comes to check the file content, so we had the idea to reuse Fest String assertions on the content of a file.
See the example below :
File xFile = writeFile("xFile", "The Truth Is Out There");
// classic File assertions
assertThat(xFile).exists().isFile().isRelative();
// String assertions on the file content : contentOf() comes from Assertions.contentOf static import
assertThat(contentOf(xFile)).startsWith("The Truth").contains("Is Out").endsWith("There");
Note that it is meant to be used with small files since the whole content is loaded in memory.