I found that it is so hard to test classes that depend on other utility classes as java.nio.file.Files. It is also impossible to mock them using the classic unit testing stack (junit,mockito,..) unless you use other heavy mocking frameworks like powermock which i consider a bad practice in case of building projects from scratch and also a nightmare if you try to integrate it with maven plugins ( surefire, jacoco ,offline instrumentation,...)
So what i've decided to do to ease my unit testing, is to wrap this utility classes inside a normal instantiable class and inject them to my main class as follows:
public class IOManager {
private final FileSystemUtilsWrapper fileSystemUtilsWrapper;
private final HttpUtilsWrapper httpUtilsWrapper;
public IOManager() {
this.fileSystemUtilsWrapper = new FileSystemUtilsWrapper();
this.httpUtilsWrapper = new HttpUtilsWrapper();
}
public IOManager(
FileSystemUtilsWrapper fileSystemUtilsWrapper,
HttpUtilsWrapper httpUtilsWrapper
) {
if (fileSystemUtilsWrapper == null
|| httpUtilsWrapper == null) {
throw new NullPointerException("...");
}
this.fileSystemUtilsWrapper = fileSystemUtilsWrapper;
this.httpUtilsWrapper = httpUtilsWrapper;
}
public boolean doIOOperations(String filePath, String url) throws IOException {
if (fileSystemUtilsWrapper.isMyFileReachable(filePath)
&& httpUtilsWrapper.isMyURLReachable(url)) {
// do something and returns IO state
}
return false;
}
}
/**
* FileSystem utils wrapper
*/
class FileSystemUtilsWrapper {
public boolean isMyFileReachable(String filePath) {
Path path = Paths.get(filePath);
return Files.exists(path) && Files.isWritable(path);
}
}
/**
* http utils wrapper
*/
class HttpUtilsWrapper {
public boolean isMyURLReachable(String url) throws IOException {
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url)
.openConnection()
;
// i keep it simple
return urlConnection.getResponseCode() == 200;
}
}
I just keep it simple for the sake of getting a quick insight.
Note that i've also considered using directly utility classes inside my SUT and mocking the I/O resources (creating and deleting a dummy file and using wiremock to mock the http endpoint ). While it may seem the easiest path to take, IMO one shouldn't do so, because it is not unit testing anymore but integration tests.
I would appreciate hearing your opinion on my analysis. thanks in advance and Best Regards,
separation of concerns ( integration from unit testing)
-- Those two things don't have anything to do with each other.isn't going to produce benefits
-- Why not?unit tests are faster than integration tests
-- Debatable, but what does that have to do with anything?sometimes advisable to have more tests
-- The quality of your tests is more important than the number of tests you have.Debatable, but what does that have to do with anything?
i've seen so many projects that depend more heavily on integration tests than unit tests for regression detection, and sometimes they sacrifice unit tests for integration tests (unit tests are useless to them) ,the example i give is so simple and limited to the question's scope, but anyway i understand your idea, the problem is if one starts to mix unit tests with integration, it would become unmaintainable, this why i think we should have both separated (in the ideal word, no deadlines,...).