Refactor towards test: static helpers
I often face lagacy code which has a lack of tests and is not designed to be tastable.
A typical problem are static methods used by components you want to test but cannot be mocked (except using tools like PowerMock which for me acts more like an air freshener for code smells). To start writing unit tests, it is helpful to refactor the static helper to become an injected dependency.
First step is to introduce a static singleton instance to be able to make methods non static later:
class MyHelper { static boolean isWhatever(MyType param) {…} }
Second we copy all public methods and replace the old static ones by using the singleton instance:
class MyHelper { static final MyHelper INSTANCE = new MyHelper(); static boolean isWhatever(MyType param) { return INSTANCE.isWhatever(param); } boolean isWhatever(MyType param) {…} }
Third step is to inline all invocations of the static method usage:
class MyHelper { @Deprecated static final MyHelper INSTANCE = new MyHelper(); boolean isWhatever(MyType param) {…} }
Last step is to make the singleton an injectable bean. With Spring framework this can look like the following:
@Component class MyHelper implements FactoryBean<MyHelper> { @Deprecated static final MyHelper INSTANCE = new MyHelper(); boolean isWhatever(MyType param) {…} MyHelper getObject() { return INSTANCE; } CLass<MyHelper> getObjectType() { return MyHelper.class; } boolean isSingleton() { return true; } }
Now you can start to replace usages of INSTANCE by injection. This can be done step by step. You may have to live with this state for a while.
At the end the factory bean implementation and the static singleton field can be removed.
@Component class MyHelper { boolean isWhatever(MyType param) {…} }
Now we reached more or less the original amount of code. Was it worth to do so?
If you have a lot of usages of such static helpers it is, because you can do the refactoring in small controlled steps and not in a long living branch with the need to solve merge conflicts again and again. And you are able to benefit from improved independent unit tests very fast even with a partial refactoring that can be paused and go live in any step.









