viernes, julio 22, 2011

Tu I Jo Asseguts A La Barra D’un Bar, Sona Bona Música I Som Davant Del Mar (Al Mar - Manel)

In current post I am going to talk about differences between Hamcrest and Fest Fluent Assertions. The reason of this post is not to tell you if you should use one or the other. I only want to show you how both implementations resolve the problem of writing readable assertions.

To compare both APIs I have created two JUnits, one using Hamcrest assertions and one where Fest assertions are used.

The comparision is done using only common operations (Logical, Object, Collections, Number, Text) and creation of new matchers. I am not going to compare which ones have implemented more matchers or kinds of matchers, because I think this is not a parameter to use for choosing what library fits better to your project. Moreover in both APIs you can extend them for creating your own matchers.

Let's start showing model representing a simple modelling of Studio Ghibli movies information. 


Hamcrest requires 11 imports:

while Fest requires 2 imports:

in fact this is not a good or bad thing how many imports are required, but it is always a headache remember where a required assertion is packaged. Because Fest uses Fluent Interfaces approach with two imports all operations are available with IDE's "auto-completation" feature.

Simple asserts:

Not much difference between Hamcrest and Fest, in case of Fest verb is also added in method name creating a much readable assert.



Logical asserts:

In this case we find a big difference. Hamcrest supports logical operations and can be used independently, meanwhile logical operations in Fest are a part of the method:



Object asserts:

Same object operations are provided in both APIs. There is only one difference, in Fest you can chain callings of methods, so number of asserts compared to Hamcrest are fewer.



Collection asserts:

In case of Collections is where they differ more from each other. Hamcrest deals with Collections and Maps with methods like hasKey, hasValue, hasItem. Fest uses a more generic calling like includes, excludes, entry; I have not found any way for asserting key instead of key-value in Fest.
Moreover in this example I also compare how to access a bean property in each elements of collection. From my point of view I think that Fest has a better approach resolving this case.



Number asserts:

As in simple asserts, there is no much difference between them.



String asserts:



As you have noted Hamcrest and Fest are very similar, but I think that Fest solves the same problem but in much cleaner way.

Although both solutions offer very similar matchers, each implementation is so different, so creation of a custom matcher is different too. In Hamcrest you should create a class that extends from TypeSafeMatcher. In Fest there are two possibilities, first one is extending Fest-assertions with custom condition (using already Fest structure and defined types), and the second one is extending with custom assertion (creating a new assertThat implementation for required type).

Hamcrest extension for asserting that a character is a human:

In case of Fest there are two approaches, the first one, that requires that our class extends from Condition. As I told previously, extending Condition implies using the same kind of types supported by org.fest.assertions.Assertions.assertThat method (object, int, short, list, array, ...). In previous case our type is Character, and of course does not exist an overload of Assertions.assertThat method with Character, but java.lang.Object. So our class should be:

As you probably noted, you need to cast character variable to Character, neither a clean solution nor optimal. But of course you can use second method, extending from GenericAssert. This class (a Fluent class) will be the responsible of implementing an assertThat that accepts Character objects, and moreover will implement matcher methods. And I say methods because unlike Hamcrest, Fest can contain more than one matcher in each class. For example if there are some tests that we are asserting if character is human, and in another ones asserting if is human and if has a name, in Hamcrest we should create two classes. In Fest you don't have this restriction.

As it is told in Fest site "Which one to use? Hamcrest or FEST-Assert? It is up to depends on the needs of your project and your coding style!"

Download code.


3 comentarios:

Anónimo dijo...

First, thank you for the comparison. This is the first I'd seen of Fest, and it definitely looks good.

Just some suggestions for your usage of Hamcrest:

1. For imports, you should be using the Matchers factory class rather than importing each individual item. Can statically import Matchers.*.

2. For chaining multiple matchers, can use the allOf matcher to combine them. Not as clean as Fest's implementation, but at least makes it clearer that they all must be true, and are all applicable to one actual value.


Alex dijo...

Hi Mike thank you very much for your comments, I agree with you that importing Matchers class, you avoid having to import each class.

About allOf operation it is true that you can acquire the same behavior with allOf but as you said it is not a clean solution.

Thank again for your comments.

Paul Duffin dijo...

What about anyOf() and not()? You cannot do either of those in FEST unless you use is and roll your own Condition instances which are basically Hamcrest matchers.