There are only so many ways to test that your persistence layer is implemented correctly or that you’re using an ORM correctly. Here’s my canonical tests for a repository (Java-version):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import static org.fest.assertions.api.Assertions.*; public class PersonRepositoryTest { private PersonRepository repository; // TODO < == you must initialize this @Test public void shouldSaveAllProperties() { Person person = samplePerson(); repository.save(person); // TODO: Make sure your repository flushes! assertThat(repository.find(person.getId()) .isNotSameAs(person) .isEqualTo(person) .isEqualsToByComparingFields(person); } @Test public void shouldFindByCaseInsensitiveSubstringOfName() { Person matching = samplePerson(); Person nonMatching = samplePerson(); matching.setName("A. Matching Person"); nonMatching.setName("A. Random Person"); repository.save(matching); repository.save(nonMatching); assertThat(repository.findByNameLike("MATCH")) .contains(matching) .doesNotContain(nonMatching); } } |
Very simple. The samplePerson
test helper generates actually random people:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class PersonTest { // .... public static Person samplePerson() { Person person = new Person(); person.setName(sampleName()); // TODO Initialize all properties return person; } public static String sampleName() { return SampleData.randomWord() + " " + SampleData.randomWord() + "son"; } } public class SampleData { public static String randomString() { return random("foo", "bar", "baz", "qux", "quux"); // TODO: Add more! } public static <T> T random(T... options) { return options[random(options.length)]; } public static int random(int max) { return random.nextInt(max); } private static Random random = new Random(); } |
If your data has relationships with other entities, you may want to include those as well:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class OrderRepositoryTest { private OrderRepository repository; // TODO < == you must initialize this private PersonRepository personRepository; // TODO <== you must initialize this private Person person = PersonTest.samplePerson(); @Before public void insertData() { personRepository.save(person); } @Test public void shouldSaveAllProperties() { Order order = sampleOrder(person); repository.save(order); // TODO: Make sure your repository flushes! assertThat(repository.find(order.getId()) .isNotSameAs(order) .isEqualTo(order) .isEqualsToByComparingFields(order); } |
A simple and easy way to simplify your Repository testing.
(The tests use FEST assert 2 for the syntax. Look at FluentAssertions for a similar API in .NET)
(Yes, this is what some people would call an integration test. Personally, I can’t be bothered with this sort of classifications)
1) Shouldn’t the test name be “shouldFindByName”? (“By” instead of “B”)
2) I am confued by setting the name to “A. Matching Person” but using “MATCH” in
repository.findByNameLike(“MATCH”). I suppose that Like is case-insensitive substring match –
I would prefere to have these two properties (substring, insensitive) mentioned either in the test’s name
or at least in a comment. But perhaps in your team the meaning of Like is clear so this info isn’t needed.
BTW, I could not log-in with Twitter using FF, it just opens this blog in a new window. Ok in Chrome.
Thanks for the comment, Jakub. I’ve changed the name to shouldFindByCaseInsensitiveSubstringOfName
Pingback: Most interesting links of April ’13 « The Holy Java
With the TDD we need to construct our code (or the solution ) with the series of tests. But if the application environment is heavy ( If applications loads hundreds of hibernate entities at the start-up) , I feel this tests makes some slowness on the coding. Am i right ? I felt this with a legacy application.. What are the practices to overcome this kind situations ..
Hi Kasun
It was good to see you at the coding dojo tonight
The most important goal is to find a way to test the application without the slower parts like Hibernate. This can either be by faking/mocking the repository layer in most other tests, or by avoiding slow tech like Hibernate altogether. The latter is of course not always an option.
When mocking/faking the Repositories, you still need a set of test to run the cover the actual repository information (that’s the kind of tests I list here).