Mark Needham

Thoughts on Software Development

Archive for the ‘Hibernate’ tag

Testing Hibernate mappings: Setting up test data

with 3 comments

Continuing with my mini Hibernate mappings series, this post talks about the different ways of setting up the test data for our Hibernate tests.

  1. Where to test the mappings from?
  2. How to test for equality?
  3. How to setup the test data?

There are a couple of ways that we can setup data for Hibernate tests.

Insert Hibernate Object

This approach involves creating a new object and saving it to the database using the save method on the Hibernate session.

The benefit of this approach is that our test is pretty clean. It looks like any old unit test where we create an object and then check that what we get back is the same object.

The problem is that we are effectively testing two things – the ability to save and then load our Hibernate object. We will be able to tell whether or not our Hibernate mappings are correct using this approach, but the failures we get when they do fail may not be that obvious – it could just be a database exception which makes the test fail.

SQL Insertion

The other approach I have seen is to write manual JDBC calls to insert data into the various tables in our database and then check that we can load our object from the database using Hibernate.

The advantage of this is that our test is now only testing the mappings when we load the data from the database which helps reduce our test’s invariants or potential points of failure.

The disadvantage is that the tests can seem very brittle – if we make a small change to the column names in our tables then the test setup code may now fail to work anymore.

I’m not really completely happy with either of these approaches – neither seems optimal to me but both can help us achieve our objective. It’s just a matter of choosing which trade off we’ve prepared to accept.

Written by Mark Needham

October 30th, 2008 at 11:24 pm

Posted in Hibernate,Testing

Tagged with ,

Testing Hibernate mappings: Testing Equality

with 2 comments

I started a mini Hibernate series with my last post where I spoke of there being three main areas to think about when it comes to testing:

  1. Where to test the mappings from?
  2. How to test for equality?
  3. How to setup the test data?

Once we have worked out where to test the mappings from, if we have decided to test them through either our repository tests or directly from the Hibernate session then we have some choices to make around how to test for equality.

I’ve seen this done in several ways:

Override equals

This was the first approach I saw and in a way it does make some sort of sense to test like this.

We don’t have to expose any of the internals of the class and we can get feedback on whether our objects have the same fields values or not. In addition we can normally get the IDE to generate the code for the equals method so it doesn’t require much extra effort on our behalf.

Typically an equality test along these lines would look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Entity
public class Foo {
	@Column(name="BAR")
	private String bar;
 
	public Foo(String bar) {
		this.bar = bar;
	}
 
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
 
        Foo foo = (Foo) o;
 
        return !(bar != null ? !bar.equals(foo.bar) : foo.bar != null);
 
    }
}
1
2
3
4
5
6
import static org.hamcrest.MatcherAssert.assertThat;
...
Foo expectedFoo = new Foo("barValue");
Foo foo = getFooFromHibernate();
 
assertThat(foo, equalTo(expectedFoo));

The problem with this approach is that objects which are in Hibernate are likely to be entities and therefore their equality really depends on whether or not they have the same identity, not whether they have the same values. Therefore our equals method on the object should only compare the id value of the object to determine equality.

Implementing the equals method just for testing purposes may also be considered a code smell.

Getters

This approach involves adding getters to our objects to check that the values of each field have been set correctly.

While this approach is marginally better than not testing the mappings at all, the temptation to then use these getters in other pieces of the code can lead to us having objects with no behaviour at all with our logic spread all over the application.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class Foo {
	@Column(name="BAR")
	private String bar;
 
	public Foo(String bar) {
		this.bar = bar;
	}
 
	public getBar() {
		return this.bar;
	}
}
1
2
3
4
5
6
import static org.hamcrest.MatcherAssert.assertThat;
...
String bar = "barValue";
Foo foo = getFooFromHibernate();
 
assertThat(foo.getBar(), equalTo(bar));

Reflection

An approach I was introduced to recently involves using reflection to check that Hibernate has hydrated our objects correctly.

We initially rolled our own ‘Encapsulation Breaker’ to achieve this before realising that the OGNL library did exactly what we wanted to do.

By adding a custom Hamcrest matcher into the mix we end up with quite a nice test for verifying whether our mappings are working correctly.

1
2
3
4
5
@Entity
public class Foo {
	@Column(name="BAR")
	private String bar;
}
1
2
3
4
import static org.hamcrest.MatcherAssert.assertThat;
...
Foo foo = getFooFromHibernate();
assertThat(foo, hasMapping("bar", equalTo("someValue")));
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
31
public class HasMapping<T> extends BaseMatcher<T> {
    private String mapping;
    private Matcher<T> mappingValueMatcher;
 
    public HasMapping(String mapping, Matcher<T> mappingValueMatcher) {
        this.mapping = mapping;
        this.mappingValueMatcher = mappingValueMatcher;
    }
 
    public void describeTo(Description description) {
        description.appendText("A mapping from ");
        description.appendText(mapping);
        description.appendText(" that matches ");
        valueMatcher.describeTo( description );
    }
 
    @Factory
    public static <T> HasMapping hasMapping(String mapping, Matcher<T> mappingValueMatcher) {
        return new HasMapping(mapping, mappingValueMatcher);
    }
 
    public boolean matches(Object o) {
        try {
            Object value = OgnlWrapper.getValue(mapping, o);
            return mappingValueMatcher.matches(value);
        } catch (OgnlException e) {
            return false;
        }
    }
 
}

The drawback of this approach is that if we change the names of the fields on our objects we need to make a change to our test to reflect the new names.

I ran into the example dilemma a bit while writing this but hopefully the ideas have been expressed in the code presented. I didn’t want to put too much code in this post but if you’re interested in what the OgnlWrapper does I posted more about this on my post about Java checked exceptions.

Written by Mark Needham

October 29th, 2008 at 6:03 pm

Posted in Hibernate,Testing

Tagged with ,

Testing Hibernate mappings: Where to test from?

with 3 comments

I’ve had the opportunity to work with Hibernate and it’s .NET twin NHibernate on several of my projects and one of the more interesting decisions around its use is working out the best way to test the hibernate mappings that hook together our domain model and the database.

There are three decisions to make around how best to do this:

  1. Where to test the mappings from?
  2. How to test for equality?
  3. How to setup the test data?

This post will focus on the ways I have seen with regards to choosing where to test the mappings from.

Functional Tests

This approach advocates only testing whether we have setup the mappings correctly when we run our acceptance or functional tests – we do not write tests specifically for testing hibernate mappings.

The benefit of this approach is that we are more likely to have acceptance tests in place, so this is just another thing that they can be used to catch.

While this approach is better than not testing at all, from my experiences the test feedback cycle is too slow – it takes too long to change one of the hibernate mappings and then run the test to check if it worked or not.

Repository Tests

With this approach we test whether our hibernate mappings are working as part of our repository tests.

The tricky thing with testing our hibernate mappings this way is that typically we only want to set up one object in the database and then test that Hibernate hydrates it correctly, but our repository doesn’t necessarily need a method for finding a single object.

We either end up adding on a method just for testing or we have to try and find our object from a list of other objects and then test it.

On the other hand, this approach does seem to work quite well when we have quite chatty repositories which provide a degree of flexibility around how we can retrieve our objects.

Direct Tests

This approach is my current favourite and involves loading the object directly from the Hibernate session and then testing it.

I was introduced to this idea by a colleague of mine and it seems to fit the idea of testing just one thing more closely than the other two approaches.

The strange thing about this approach is that we are testing directly with an API that is hidden from our system beyond the Repository.

In terms of simplicity with regards to testing hibernate mappings, however, this is the best approach I have seen.

I did a quick survey of some people last week and the most popular way of testing the mappings expressed was using Repository tests.

This post covers the other ways I have seen – are there any others people have come across or are using?

Written by Mark Needham

October 27th, 2008 at 10:55 pm

Posted in Hibernate,Testing

Tagged with , ,