Unit testing bad code is hard. If it is not designed to be tested than odds are it will be hard to test. One of the biggest thorns in my side has been trying to unit test classes that use static methods to access resources.
Static methods tend to be used quite a bit in older code. The singleton pattern was pretty popular in the java world, especially when dealing with resources. Unfortunately, when we are unit testing, we want to avoid dealing with these resources.
Take this fragment for example:
public class AwesomeClass {
public void performAwesome() {
// some code
AwesomeUtil.talkToServer();
// some more code
}
}
public class AwesomeUtil {
public void static talkToServer() {
// code to connect and communicate with a server
}
}
Testing performAwesome is made more complicated because of the static method. It talks to a server, and that would make this an integration test (which we want to avoid). We could use a mocking framework that supports static rewriting, but I am not a huge fan of that (I love mocking, but I prefer using OO to solve this particular problem because it tends to lead to better design decisions when making good code).
Ideally we would have a free hand and refactor it fully using an IoC framework such as spring, but that rarely happens, and would add a huge load on QA if we did. One of the nicest tricks I have learned is to do a micro-refactoring.
public class AwesomeClass {
public void performAwesome() {
// some code
talkToServer();
// some more code
}
public void talkToServer() {
AwesomeUtil.talkToServer();
}
}
This modification to the code is logically equivalent. The only change is that the call to the static method is now handled in a non-static function in our class. It is a very simple and low risk change.
And it allows the following:
public class AwesomeClassTest {
int talkedToServerCount;
AwesomeClass awesomeClass
@setUp
public void setUp() {
talkedToServerCount = 0;
awesomeClass = new AwesomeClass() {
talkToServer() {
++talkedToServerCount;
}
}
}
}
I find that pretty cool. The version of the class we are testing no longer has a static method, and we can not test is as we would any other class.