Static classes and unit testing

If you unit test your code (and I hope you do), you’ll quickly discover that you need to mock out parts of the system. This is much easier if you design with testability in mind from the start of the project. In particular, as you’ll see, you need to be very careful about where you use static classes.

Generally when people first learn about object oriented programming it takes a while for the concepts to sink in. If you’re used to procedural languages the world of objects can seem strange and full of unnecessary bloat: why are my functions called ‘methods’, and why do I have to put them all in this thing called a ‘class’? Beginners end up creating classes full of static methods, mimicking the style of procedural programs. Unfortunately a lot of experienced programmers do the same thing. A static method can look like a deceptively simple solution but often there are good reasons to create a fully fledged class instead.

When it’s OK

But first of all, let’s look at the situations when it really is OK to use a static method. To do that I’m going to borrow a term from functional programming called ‘referential transparency’. For example, here’s a method which is referentially transparent:

boolean emailAddressIsValid(String email) { ... }

It carries out some tests on the email address and returns a boolean value. Perhaps it checks that it contains the @ and at least one dot in the domain section. The important part is that it doesn’t do anything else - it doesn’t interact with the screen or the keyboard, call a database, or modify any values elsewhere in the program. All these things are ‘side effects’. Pure functional programmers believe that functions should never, ever, cause side effects, but if you followed this at work your programs wouldn’t ever do anything and your boss might not be happy.

You can put all your methods into two categories: ones that cause side effects, and ones that don’t. If a method is side-effect free, all its dependencies (the methods it calls) have to be side-effect free as well. You’ll never need to mock these methods, so they can be made static. To look at it another way, consider that a method like this doesn’t change the state of the program or it’s environment. As object-oriented classes are essentially a representation of state, there’s a sense in which this method exists independently, and doesn’t need to be associated with an instance of an class.

When it’s not

All the other methods cause side effects. If a method calls a database, or sends an email, it’s pretty clear that you’ll need to mock it at some point down the line. Even methods that print output to the screen or read keyboard input should be mockable, if you ever want to test their behaviour.

The object-oriented solution to this is polymorphism. This means creating a base class, or preferably an interface for more flexibility, and coding against the interface rather than the implementation. This is the open/closed principle in action. You’ll still need to create the concrete class at some point, and dependency injection and inversion of control are useful techniques here. But if the class was static, none of this would be possible and you would lose all the benefits of OOP.