Tips for (unit testing) JavaBeans

If you’re writing Java code chances are you’re writing at least a few classes that adhere to the JavaBean conventions, i.e., classes that have private properties with public getter and setter methods, contain a no-arguments constructor, are serializable, and comply with the Equals and HashCode contract. And on top of that you’ll probably also throw in a useful toString() implementation.

If, e.g., we take a very simple class called MyBean that contains two fields named id and name, we’ll end up with the following code:

MyBean - a JavaBean example

Java

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

packageit.jdev.example;

importjava.io.Serializable;

publicclassMyBeanimplementsSerializable{

privatestaticfinallongserialVersionUID=6170536066049208199L;

privatelongid;

privateStringname;

publicMyBean(){

super();

}

publiclonggetId(){

returnid;

}

publicvoidsetId(finallongid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(finalStringname){

this.name=name;

}

@Override

publicinthashCode(){

finalintprime=31;

intresult=1;

result=prime*result+(int)(id^(id>>>32));

result=prime*result+((name==null)?0:name.hashCode());

returnresult;

}

@Override

publicbooleanequals(finalObjectobj){

if(this==obj){

returntrue;

}

if(obj==null){

returnfalse;

}

if(getClass()!=obj.getClass()){

returnfalse;

}

finalMyBean other=(MyBean)obj;

if(id!=other.id){

returnfalse;

}

if(name==null){

if(other.name!=null){

returnfalse;

}

}elseif(!name.equals(other.name)){

returnfalse;

}

returntrue;

}

@Override

publicStringtoString(){

return"MyBean [id="+id+", name="+name+"]";

}

}

So for a class with just two fields, we’ve ended up with 70 lines of code. That is a lot of boilerplate code. And furthermore, every time you add or change any properties you will have to adjust or regenerate alot of that boilerplate code.

Project Lombok to the rescue

Luckily, there is a nice open source tool that aims to reduce just the type of boilerplate code we’re dealing with in our MyBean class. It is called Project Lombok. Just install Lombok as a plugin in your favourite IDE, and include the Lombok jar file on your build classpath or add it as a maven dependency, and you should be good to go.

Project Lombok contains alot of different annotations but for our example we’re only going to need one: @Data. When we apply the annotation to our code we’re down to a mere 15 lines of code from our original 70 lines, with Project Lombok generating all the methods for us during compilation. And moreover, we never again have to worry about our hashCode(), equals(), and toString() methods running out-of-sync.

MyBean - our JavaBean example with Project Lombok

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

packageit.jdev.example;

importjava.io.Serializable;

importlombok.Data;

@Data

publicclassMyBeanimplementsSerializable{

privatestaticfinallongserialVersionUID=6170536066049208199L;

privatelongid;

privateStringname;

}

Help, my code coverage is down

The fact that we now have Project Lombok generating the boilerplate code for us, doesn’t necessarily mean that we can skip unit testing the generated methods. Especially if you value code coverage, and you have minimal coverage level checks in place in your CI set-up, you’ll want to add some extra tests. Luckily, there are some easy ways to get your code coverage up.

Testing Serializability

If your serializable objects contain any custom fields, these probably should also be serializable. However, this is something that is easily overlooked. Using the SerializationUtils class from the Apache Commons Lang library, you can write a very simple test that checks whether an object correctly serializes, and deserializes back again.

Testing getter and setters methods

Testing the getter and setter method pairs of a JavaBean can become very tedious very quickly. Fortunately there is a nice test library called meanBean that can do the work for us. So after adding the following method to our unit test, we’re finished testing the getters and setters:

Testing the getters and setters of our MyBean example

Java

1

2

3

4

@Test

publicvoidgetterAndSetterCorrectness()throwsException{

newBeanTester().testBean(MyBean.class);

}

Testing equals() and hashCode()

Testing all the intricacies of the equals and hashCode contract yourself is a very wearisome task. Again, there are some nice tools that can take it off your hands. The aforementioned library meanBean offers functionality to do so. However, I found a tool like EqualsVerifier to be a tad more stringent in its tests, and it also provides detailled explaination about any errors. So we’re going to add the next test case to our suite:

A common base class for our JavaBean test cases

Even with tools like meanBean and EqualsVerifier doing the heavy lifting, you don’t want to repeat the same test code over and over again. So you’ll probably will want to put the tests in an abstract base class. A possible implementation of that base class could look something like the following:

6 Replies to “Tips for (unit testing) JavaBeans”

I really do not think we should waste our time to write tests for something such trivial (and beans are already covered by plethora of other unit and non-unit tests). I can’t recall a single case when such test would had saved my ass from some dready bug in beans (because it is really, really hard to make any mistakes while writing beans).

Thanks for your comment. I can (partly) agree with you as far as the trivial getters and setters are concerned, but only for these. As you noted, these accessor methods usually get covered indirectly by other, more meaningful unit tests.

However, in my experience it sometimes can be very tricky to get the rest of the bean contract – especially the hashCode() and equals() – working correctly and more, have it remaining to function correctly over time.

And what about the Serializable interface? For example, have you ever worked with JPA/hibernate and forgot to implement Serializable? I know I have.

So, I do think there’s more to the JavaBean specification than only trivial getters and setters, and that part of the JavaBean contract is something that we do have to test to ensure that our classes are and will remain correct. And when you’re already at it, why not have some tests generated for those getters and setters to get the coverage up, if only to satisfy your corporate QA policies 😉