Unit Testing Static Methods of the Java Standard Library
We’ve all been at a point where in we’re writing up test cases for our application and we encounter a static method from the java
standard library being called. Everything goes downhill from there. Mockito would give you ambiguous error messages. Notice there is no reason shared as to why is it throwing a NullPointerException
and this is at the time of mocking.
Prerequisites
This post does expect some familiarity with Unit testing
using frameworks like Mockito
. The code sample is in Java 8
and does require one to have an understanding about Functional Interfaces
and Lambda functions
in general. But it’s not something you would need in depth understanding of. If you’re not from a Java background, don’t worry the code is fairly straight forward and readable, so you would be able to follow along.
What about other frameworks?
That’s a fair question. What about PowerMock
? While I was researching on the topic I came across the PowerMock git repo, which explicitly states:
Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability.
It helps unit test these methods but I could never make my peace with using a whole framework for just a few usages here and there. If you’d rather use a framework instead, then there are a lot of frameworks and the most popular one is PowerMock.
The example
For the simplicity of the blog post, let’s assume you’re writing a method that gets a rootDirectory
and a fileName
. The method needs to return the contents of the file. Now if using Java
you would use the java.nio.file.Files
API to call a method called walk()
to iterate through all files in the directory and then you would use the readAllBytes()
method in the java.nio.file.Files
to read the contents of the file. The overall code would look like
The problem is, the java.nio.file.Files.walk()
method and java.nio.file.Files.readAllBytes()
method are both static
. This causes a problem in unit testing this code since, we would not be able to mock
the responses of these methods.
Functional Interfaces to the rescue
What we can notice, is that we are using two methods walk()
and readAllBytes()
and we don’t quite need any other method which is a part of java.nio.file.Files
class.
The intuition is to create two functional interfaces, FileReader
(reads all files in a directory) and ContentReader
(reads the content of a single file) each doing one part of the process. Now instead of using java.nio.file.Files
class, we inject the two Functional Interfaces
using Constructor Injection
.
Below is the updated code.
Now you can simply use Mockito
to mock the dependencies using the @Mock
and then use Mockito
fluent syntax to mock the behaviour.
when(mockedFReader.fetchFilesInDirectory(any())).thenReturn(sample);
Why Functional Interfaces and not a Util class?
The answer is code coverage. Considering you create a new class and wrap the Files
class methods, you still would have to deal with code coverage issues. Although, to test out your FileOperator
class, you can mock dependency, you still have zero
coverage on your Util class. Is that a good practice or not? is opinion based.
Also, using functional interfaces make it easier to inject dependencies especially when using a Dependency Injection framework
like Spring
.
Conclusion
In this blog post we looked at how to make the code that uses java standard library static methods, more testable.
I do not recommend you make Functional Interfaces for all your static methods because you can always refactor your code to make it more unit testable but when it comes to the java standard library, things become out of our hands.
Like this article? Please consider following @iam_Carrot on Twitter. Maybe click the clap👏 button a few times to show your support ⬇⬇