Every time I was trying to test an object's properties I was neither satisfied writing very verbose tests nor in using some of the out of the box hamcrest matchers. Although using the matchers was a big help, I never managed to make them read the way I wanted.
Another thing that was very important to me, I wanted to have a single assertion per method and a very descriptive description if the test did not pass.
I've decided to write my own matcher and hopefully it will be useful to other people. So, that's what I've done:
NOTE: Make sure you are using org.hamcrest.MatcherAssert.assertThat instead of the JUnit one.
If you run this test, you will get a message like
Now, change the age check to
I use a combination of two matchers to do that:
- BeanMatcher: Provides the "has" method responsible to group all the property matchers.
- BeanPropertyMatcher: Provides the "property" method.
I expect to make more changes to them, so for the most up-to-date version, please check BeanMatcher on my github account.
Enjoy!!!
Another thing that was very important to me, I wanted to have a single assertion per method and a very descriptive description if the test did not pass.
I've decided to write my own matcher and hopefully it will be useful to other people. So, that's what I've done:
BeanMatcher
Hamcrest matcher to match multiple attributes of an object within a single assertion.How to use it
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Static imports | |
import static org.craftedsw.beanpropertymatcher.matcher.BeanMatcher.has; | |
import static org.craftedsw.beanpropertymatcher.matcher.BeanPropertyMatcher.property; | |
import static org.hamcrest.MatcherAssert.assertThat; | |
import static org.hamcrest.Matchers.equalTo; | |
import static org.hamcrest.Matchers.greaterThan; | |
// Imagine that you have a method that returns an object Person | |
Person person = new Person(); | |
person.setFirstName("Sandro"); | |
person.setAge(25); | |
person.setLastName("Mancuso"); | |
// Then you can test it like that | |
assertThat(person, has( | |
property("firstName", equalTo("Another dude")), // Mistmatch | |
property("age", greaterThan(18)), // Use any matcher | |
property("lastName", equalTo("Mancuso")))); |
If you run this test, you will get a message like
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
java.lang.AssertionError: | |
Expected: property "firstName" = "Another dude" | |
but: property "firstName" was "Sandro" |
Now, change the age check to
And you should get:property("age", greaterThan(60))
Testing object graphs
You can also do this
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Person person = new Person(); | |
person.setFirstName("Sandro"); | |
person.setAge(35); | |
Country uk = new Country(); | |
uk.setName("United Kingdom"); | |
Address address = new Address(); | |
address.setPostcode("1234556"); | |
address.setCity("London"); | |
address.setCountry(uk); | |
person.setAddress(address); | |
assertThat(person, has( | |
property("firstName", equalTo("Sandro")), | |
property("age", greaterThan(18)), | |
property("address.city", equalTo("London")), | |
property("address.postcode", equalTo("1234556")), | |
property("address.country.name", equalTo("United Kingdom")))); |
- BeanMatcher: Provides the "has" method responsible to group all the property matchers.
- BeanPropertyMatcher: Provides the "property" method.
I expect to make more changes to them, so for the most up-to-date version, please check BeanMatcher on my github account.
Enjoy!!!