Testable Java

Lately I have been modifying some code other people have written. There are some things about writing Java that I consider fairly basic, but not so I find. I will elaborate.

We use Spring Framework a lot. Spring supports the dependency injection concept and, used properly, makes life much simpler. To use it properly the idea is to ‘inject the dependencies’ (well, obviously, you’d think).

Dependency Injection

One of the huge advantages with this approach is that the code is more testable. You might have a class A which depends on class B. Without dependency injection you’d probably hard code a ‘new B()’ in class A, or have B a static class, and then call it. That means when you want to test A you necessarily have to test B. You can’t mock it out.

It is much better to create a triplet of:

  • B the interface
  • BImpl the production code
  • BMock a mock implementation that does very little

Then you add a field of type B to class A with a setter and getter. When you write a unit test for A you set BMock into it so A calls BMock rather then BImpl when it is being tested.

Otherwise you find that to just test one class you have to do a massive amount of work to set up all the dependencies and their dependencies etc. Let’s say B is a DAO which requires a database. BMock does not, it just returns some hard coded values. Now A’s unit test (which uses BMock) needs no database. That’s a help.

Sometimes there is more than one BImpl, for example you might want a version of B that fetches data from a web service or LDAP. A should not need to know anything about this (this is called encapsulation and is fundamental to OO concepts).

The instantiation of these classes is done by Spring. An XML file defines the relationships between the classes, or you can use annotations. But this post is more about Java than Spring. The point I must make is that your Java code is not doing the instantiation, otherwise it would have to know which B to instantiate.

It is worth including your mock classes in your distribution. We often find other internal projects using our classes (eg writing their equivalent of class A) and they need to use BMock to test their code. So it makes sense to bundle BMock in the same jar file as BImpl.

It makes even more sense to produce two jars and have them test against one and deploy the other, but that is more work.

Static Classes

So, is there no place for a class with a few static methods? Is that always the wrong answer?

Actually no. You should still use statics, I like to call them Utils classes, when the following criteria are met.

  • The class has no non-static internal storage (well, obviously, otherwise the static methods would not do what you want)
  • It needs to be called from lots of places and getting it injected into everywhere that needs is will be tedious.
  • It has no dependencies of its own. You can relax about JRE classes of course. You might even relax about 3rd party classes. But it should not depend on any classes you wrote yourself and anything it does depend on should be small/simple.

Consider Spring’s StringUtils as an example. It has some static methods that manipulate Strings. Lots of code calls it and it depends on nothing else. Also there is only one StringUtils. There aren’t several variations with different code needing different kinds of StringUtils.

But pretty much everything else needs to be an Interface/Impl/Mock triplet.

Configuration

Sometimes you want to inject values into your classes rather than other classes. You might have a class that sends messages to a web service and you want to configure that externally. This allows people to adjust the final address used at deployment time. There are several ways to do this:

  • Spring allows you to load properties from one or more properties files and use them in your bean definitions.
  • MaduraConfiguration allows you to specify the values in an Apache Configuration file and (again) inject them into your classes by specifying them in the bean definition.

No doubt other people have other variations. But one thing you should never do is inject your configuration scheme into your class and have the class call it. The class should be unaware of where the configuration information came from. Something called the setter which told it the value.

That has two advantages. First, you can change the way you configure things without having to change the configured classes. They never knew what was doing the configuring so there is no need for them to change.

Second, you can avoid writing a mock configuration source for your class to call if it never calls anything to do configuration. This saves a little work.

Conclusion

This isn’t the whole story but hopefully it gives an idea of how to make the code you write more testable.

2 Comments


  1. This is a topic that is near to my heart… Cheers! Where are your contact details though?

    Reply

    1. You already have my social media links.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *