jeudi 3 janvier 2019

Testability trick - Replace static initialiser with lazy initialiser

A simple 4-step refactoring to make code more testable.

Static initialisers are a major hurdle for testing. If you have a static initialiser that for instance performs a request to the database then you cannot access that class in a unit test. Let alone mock it. So even if you're trying to test some other class, you cannot, since the offending class is contaminating every use of it with non testability. You want to make sure to remove the static initialiser so that other classes can be tested in isolation.

The solution is to replace the static initialiser with a lazy initialiser. This will allow you to load the class for mocking. You'll probably have to also replace a static method by an instance method in order to avoid calling the real method and so properly test classes that are calling the offending class, but first things first.

Assuming that your static initialiser is initialising a static field of your class:
  1. Encapsulate the access to the field with a simple getter
  2. Use the *Extract Method* refactoring to extract all the code from the static initialiser
  3. In the getter initialise the field *if it is null* by calling the extracted method 
  4. Delete the static initialiser
Yep it's that simple! :o)

Your next step will likely be to replace the public methods using this getter by instance methods so that those can be tested (example).

Let's have a look at an example of the code before refactoring

And now here's the refactored code. Steps 1 and two are made by automated refactorings.

Having done this we can simply add an instance method as a proxy to the static method, then use the instance method instead of the static method as referred to above .