Static Methods and Unit Testing

public class Component { private Dependency dependency public Component(Dependency dependency) { this.dependency = dependency } public void componentMethod() { int imporantValue = dependency.getImportantValue(); // use 'imporantValue' to calculate stuff } }

public interface Dependency { int getImportantValue(); }

public class DefaultDependency implements Dependency { public int getImportantValue() { int value = // fetch imporant value from external service return value; } }

componentMethod()

public class MockedDependency implements Dependency { public int getImportantValue() { // mocked value return 1; } }

// without mocking Component component = new Component(new DefaultDependency()); // with mocking Component component = new Component(new MockedDependency()); // with Mockito Dependency dependency = Mockito.mock(Dependency.class); Mockito.when(dependency.getImportantValue()).thenReturn(1); Component component = new Component(dependency);

DefaultDependency

Dependency

public class Component { public void componentMethod() { int imporantValue = Dependency.getImportantValue(); // use 'imporantValue' to calculate stuff } }

public final class Dependency { public static int getImportantValue() { int value = // fetch imporant value from external service return value; } }

getImportantValue()

componentMethod()

Dependency

public class Component { public void componentMethod() { // classic use of Singleton int imporantValue = Dependency.getInstance().getImportantValue(); // use 'imporantValue' to calculate stuff } }

public final class Dependency { private static final Dependency instance = new Dependency(); private Dependency() {} public static Dependency getInstance() { return instance; } public int getImportantValue() { int value = // fetch imporant value from external service return value; } }

getInstance()

enums

public interface Dependency { int getImportantValue(); }

public final class DefaultDependency implements Dependency { private static final Dependency instance = new DefaultDependency(); private DefaultDependency() {} public static Dependency getInstance() { return instance; } public int getImportantValue() { int value = // fetch imporant value from external service return value; } }

Dependency

Component

public class Component { private Dependency dependency; public Component(Dependency dependency) { this.dependency = dependency } public void componentMethod() { int imporantValue = dependency.getImportantValue(); // use 'imporantValue' to calculate stuff } }

// without mocking, acquire Singleton instance Component component = new Component(DefaultDependency.getInstance()); // with mocking Component component = new Component(new MockedDependency()); // with Mockito Dependency dependency = Mockito.mock(Dependency.class); Mockito.when(dependency.getImportantValue()).thenReturn(1); Component component = new Component(dependency);

Dependency

Component

Dependency

Component

org.apache.commons.io.IOUtils

PowerMock.mockStatic(Foo.class); expect(Foo.bar()).andReturn("foo bar");

We all know that Interfaces allow us to write loosely-coupled components, and that this "loose-coupledness" comes-in handy during unit testing. Because we can separate the implementation from the method signatures, Interfaces allow us to mock implementations of our dependencies.Mocking dependencies is important during unit testing because it allows us to isolate the components we are testing from their dependencies -- this means that incorrect behavior from any dependency will not affect the results of our tests.Consider the following class:And the following Interface:Whose default implementation is defined as:In order for us to test, we'd have to setup our unit test environment to allow connections to the external service; and if this external service fails, our unit test would fail as well.Mocking the dependency allows us to execute our unit test without the need for an external service:Because we are providing a simple and consistent implementation, we are assured that our dependency always returns the correct value and therefore would not compromise the results of our tests. Mockito is a mocking framework which simplifies mocking. It allows us to mock dependencies with very little code and to customize our mocked behavior depending on our testing scenario:A great thing about Mockito is that it also supportsThe point that I'm trying to make is thatprovide us the flexibility to mock our implementation. Using mocking frameworks such as Mockito, we can even extend this flexibility to concrete methods.Because they are associated with the class rather than an instance, static methods cannot be overridden. In fact, most static utility classes in Java are marked as final. And because they cannot be overridden, it isSuppose that in our previous example,was implemented as a static utility class:Because we cannot overridewith a mocked implementation, there is simply no way for us to testwithout requiring a connection to the external service.You might have come across statements saying that "Singletons are evil". That is partly trueSuppose that in our previous example,was implemented and used as aSingleton:Becauseis a static method, all the evils associated with static methods apply to the Singleton as well (also applicable to Singletons implemented as).Obviously. With slight modifications, we can fix what's evil about our previous implementation:By makingan Interface and only applying the Singleton pattern to its default implementation, ourclass can be implemented exactly as the original version:Once again making it unit-testable:The above is an example of(IoC). Instead of acquiring theinstance from theclass, we let the container decide which instance ofto assign toStatic methods have their use. But because of their impact to unit testing, caution must be applied before using them. Personally, I limit my use of static methods to utility classes having small and unchanging logic (example:).If required to use static factory methods, applying Inversion of Control should help enforce unit-testablity.If you really need use static methods on your dependencies, you can use PowerMock Check this page for more information.