Reputation: 77
I have a class named A
and method method1()
in it:
Class A{
boolean method1(String path){
File procDir = new File(path);
if(!procDir.exists()){
return false`;
}
if(!procDir.canRead()){
return false;
}
}
}
Considering above code would anyone suggest, the way to mack the method1 and inner method/variables (procDir.canRead()
) .
Upvotes: 0
Views: 15232
Reputation: 140457
The first answer is: you can't with Mockito alone.
You need a mocking framework capable of mocking calls to new
. Such as PowerMock(ito) or JMockit. You can find documentation for how to do that using PowerMock here. In that sense, technically this is a solved problem - it only requires some twiddling to get it to work (if you get one of the pre-reqs wrong, it simply will not work).
But beyond that, the other answers are spot on: you created hard to test code, and now you are looking for a band-aid to work around the consequences of your inflexible design.
So instead of spending valuable time on twiddling with PowerMock(ito) - follow the advise you already got and fix the root cause of your test problem. For example by using some sort of dependency injection to provide a File object to this code (instead of having this code call new
itself).
Upvotes: 3
Reputation: 47905
You could use JUnit's TemporaryFolder rule (or, if using JUnit5, its equivalent extension) to create an input file for your test(s).
You would then ...
method1()
- to test the happy pathmethod1()
to test the !procDir.exists()
sad pathOn completion of the test JUnit will discard the temporary folder, thereby adhering to the test principle of self containment.
This approach allows you to test your code without any mocking whilst still being a self contained unit test.
Alternatively you could hide the File procDir = new File(path);
call behind an interface:
public interface FileCreator {
File create(String path);
}
With a simple implementation:
public class FileCreatorImpl implements FileCreator {
public File create(String path) {
return new File(path);
}
}
When testing, you could inject a Mock(FileCreator.class)
into the instance of the class which contains method1()
and set expectations on that instance as follows:
String filePath = "...";
File file = Mockito.mock(File.class);
Mockito.when(fileCreator.create(filePath)).thenReturn(file);
// happy path
Mockito.when(file.exists()).thenReturn(true);
Mockito.when(file.canRead()).thenReturn(true);
assertThat(sut.method1(filePath), is(true));
// sad path 1
Mockito.when(file.exists()).thenReturn(false);
assertThat(sut.method1(filePath), is(false));
// sad path 2
Mockito.when(file.exists()).thenReturn(true);
Mockito.when(file.canRead()).thenReturn(false);
assertThat(sut.method1(filePath), is(false));
Upvotes: 0
Reputation: 247133
This is a matter of design as the method is tightly coupled to File
The Explicit Dependencies Principle states:
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
With that in mind, consider refactoring the method to explicitly depend on the File
boolean method1(File procDir){
if(!procDir.exists()){
return false`;
}
if(!procDir.canRead()){
return false;
}
return true;
}
Which also inverts the creation of the dependency to a delegate external to the class/method. This also lets the method state explicitly what it actually needed.
Now that the method is decoupled the method can be tested by passing a proper File or mock.
You can also consider abstracting File
public interface FileInfo {
boolean exists();
boolean canRead()
}
as classes should depend on abstractions and not concretions.
boolean method1(FileInfo procDir){
if(!procDir.exists()){
return false`;
}
if(!procDir.canRead()){
return false;
}
return true;
}
The implementation of FileInfo
can then encapsulate an actual File
and expose the desired behavior.
For testing is should easier now to mock/stub/fake the abstraction either directly by inheritance or a mocking framework.
FileInfo file = mock(FileInfo.class);
when(file.exists()).thenReturn(true);
when(file.exists()).thenReturn(true);
subject.method1(file);
Upvotes: 0