I'm trying to understand how you can mock static methods, specifically from the static Files.class.
Basically, whenever this line executes:
Files.newInputStream(this.getPathObj(), StandardOpenOption.READ);
I want it to just return an object that is an instance of an InputStream.
The is my class with the static method I'm trying to mock.
public class JavaFileInput{
private Path path;
public JavaFileInput(Path path){
this.path = path;
}
public InputStream getInputStream() throws IOException {
return Files.newInputStream(this.getPathObj(), StandardOpenOption.READ);
}
public Path getPathObj() {
return this.path;
}
}
This is some "psuedo-ish" unit test code that obviously doesn't work, but I hope it portrays the idea of what I'm trying to accomplish.
#Mock(name="path")
private Path mockedPath = Mockito.mock(Path.class);
#InjectMocks
private JavaFileInput javaFile_MockedPath;
#Before
public void testSetup(){
javaFile_MockedPath = new JavaFileInput(mockedPath);
MockitoAnnotations.initMocks(this);
}
#Test
public void getNewInputStreamTest(){
//Setup
Mockito.when(Files.newInputStream(mockedPathObj, StandardOpenOption.Read)).thenReturn(new InputStream());
//Test
InputStream outputValue = javaFile_MockedPath.getInputStream();
//Validate
assertTrue(outputValue instanceof InputStream);
}
Does this make any sense? Has anyone ever had to do something similar? Any help would be greatly appreciated.
Thanks for your time!
I'm not clear what value your JavaFileInput provides. However, to test static methods you can look at PowerMock.
I came across the same problem: I have (own) code which modifies symlinks using nio.Files.
For testing my code without having to prepare and access the file system, I had to write an own mockable wrapper class around these functions.
Not so nice though that the nio JSR didn't consider this use case by defining an official interface and providing a non-static (=injectable) way for accessing Files. Mockito was known long before this..
Instead of using Mockito or PowerMock, you may also use a NIO2 implementation that work in memory:
memoryfilesystem
jimfs
While this won't solve all case (or let say it, it won't answer your attempt at mocking a static method) or allow you to create flawed InputStream (for example, one that would return an error when reading N bytes), this may suit your use case.
Also you ask if your case make any sense:
//Setup
Mockito.when(Files.newInputStream(mockedPathObj, StandardOpenOption.Read)).thenReturn(new InputStream());
//Test
InputStream outputValue = javaFile_MockedPath.getInputStream();
//Validate
assertTrue(outputValue instanceof InputStream);
You are testing that outputValue is indeed an instance of InputStream, which the compiler already does for you: outputValue is already an instance of InputStream, therefore asserting it is an instance of InputStream will never fails and your test is not checking what you want to check.
You'd best to test that outputValue is exactly the same instance as one returned, using a mock rather than new InputStream for example:
InputStream is = mock(InputStream.class);
Mockito.when(Files.newInputStream(mockedPathObj, StandardOpenOption.Read)).thenReturn(is);
InputStream outputValue = javaFile_MockedPath.getInputStream();
assertTrue(outputValue == is);
With standard Mockito, you can't mock static methods -- and I would question your reasons for doing so.
What do you seek to test by mocking the newInputStream method? You are merely creating a tautology -- that your method returns what you told it to return. And instanceof InputStream is a tautology as well.
It would make more sense to mock JavaFileInput to test another class that depends on it (perhaps by using a ByteArrayInputStream with sample data).
Related
I have written following code to publish some metrics around AWS Step function (its java lambda for aws)
#Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
int inProgressStateMachines = 0;
LocalDateTime now = LocalDateTime.now();
long alarmThreshold = getAlarmThreshold(input, context.getLogger());
AWSStepFunctions awsStepFunctions = AWSStepFunctionsClientBuilder.standard().build();
ListStateMachinesRequest listStateMachinesRequest = new ListStateMachinesRequest();
ListStateMachinesResult listStateMachinesResult = awsStepFunctions.listStateMachines(listStateMachinesRequest);
for (StateMachineListItem stateMachineListItem : listStateMachinesResult.getStateMachines()) {
ListExecutionsRequest listExecutionRequest = new ListExecutionsRequest()
.withStateMachineArn(stateMachineListItem.getStateMachineArn())
.withStatusFilter(ExecutionStatus.RUNNING);
ListExecutionsResult listExecutionsResult = awsStepFunctions.listExecutions(listExecutionRequest);
for (ExecutionListItem executionListItem : listExecutionsResult.getExecutions()) {
LocalDateTime stateMachineStartTime = LocalDateTime.ofInstant(
executionListItem.getStartDate().toInstant(), ZoneId.systemDefault());
long elapsedTime = ChronoUnit.SECONDS.between(stateMachineStartTime, now);
if (elapsedTime > alarmThreshold){
inProgressStateMachines++;
}
}
publishMetrics(inProgressStateMachines);
}
}
Now I am trying to unit-test this method and having some issues.
First of all, I get error that Mockito can not mock final class when i tried to mock AWSStepFunctionsClientBuilder.
Secondly, I have private methods which are being called with specific params.
The question is
How can i unit test this code? I read it somewhere that if a code isn't unit-testable then its a bad design. How can i improve this code so that its easily testable? I would prefer to keep those helper methods as private methods.
How can i mock final objects from AWS SDK to test this code? I can not use any other framework but Mockito.
You actually don't want to mock AWSStepFunctionsClientBuilder because you are actually calling AWSStepFunctions, which you'll have to mock anyway even after mocking the builder.
So make AWSStepFunctions an instance variable:
// add appropriate getter/setter as well
private AWSStepFunctions awsStepFunctions;
Where you currently call the builder to initialize awsStepFunctions, change to:
if (awsStepFunctions == null)
awsStepFunctions = AWSStepFunctionsClientBuilder.standard().build();
Now, during unit test, you can set awsStepFunctions to a mocked instance, bypassing the conditional initialization above.
[Edit] Some more thoughts based on #kdgregory's comment below:
The answer above is meant to provide a solution given the existing code structure, without requiring any major refactoring. In general though, ideally you would want to move the bulk of the code into another plain, more testable Java class, where you can properly inject dependencies, manage life cycles, etc.
I am having a function like the following.
public String getDecodedToken() throws UnsupportedEncodingException {
if (token == null) {
String token = ClassContainingStatic
.findString("static");
this.token = new String(Base64.decodeBase64(token), "UTF-8");
}
return token;
}
To test the function, I do not want to mock the ClassContainingStatic class because it will render the test useless. Rather I would like to see that if the call happened to ClassContainingStatic.findString("static") without mocking the object. Is there a way to achieve number of function call made to the real object?
Certainly possible with a bit of refactoring. If you extract the call to the static class in a separate method:
public String getDecodedToken() throws UnsupportedEncodingException{
if( token == null ){
token = createToken();
}
return token;
}
String createToken() throws UnsupportedEncodingException{
String token = ClassContainingStatic.findString("static");
return new String( Base64.decodeBase64(token), "UTF-8" );
}
Now you can create a mock or spy, and simply verify whether the method is called.
ClassUnderTest spy = Mockito.spy( new ClassUnderTest() );
String token = spy.getDecodedToken();
Mockito.verify( spy ).createToken();
I assumed the "static" string is fixed. If not, pass it as a parameter to the createToken class, and then you can adjust the verify accordingly.
I might have made a mistake in the Mockito syntax, but the general idea should be clear. Only drawback is that you need to create a package visible/protected (or even public if you want, but generally that is not the case) method so that the verify call can be made.
The basic thing you need here is called a spy in Mockito language.
While a mock is a completely new object, a spy wraps an existing instance and forwards calls to its methods to the original object by default, while at the same time supports mocking of method calls or verifying of calls.
But you have another challenge: the method you want to verify seems to be a static method. With Mockito you can't mock static methods. You have two basic options:
Refactor so that the method is no longer static and you provide the object which hosts the method on as a parameter to the constructor. This parameter then can be a mock or spy.
Use PowerMock to mock static methods. I would only accept the usage of PowerMock in legacy projects, where one needs to create tests with as little refactorng as possible. PowerMock is poerful yet clumsy, slow and prone to causing problems down the road, e.g. by creating lots of classes on the fly resulting in PermGen issues.
I'm trying to mock Lucenes IndexReader.close() to do nothing.
I thought this should work...
IndexReader reader = Mockito.mock(IndexReader.class);
Mockito.stubVoid(reader).toReturn().on().close(); // old approach
Mockito.doNothing().when(reader).close(); // new approach
but both result in the unit test calling the actual, real close method and ultimately causing a null pointer exception.
What have I missed?
As the javadoc indicates, close() is a final method. And Mockito can't mock final methods.
Imagine the following class
public class ClassToBeTested{
private AnotherClass otherClass;
public void methodToBeTested(){
otherClass = new AnotherClass();
String temp = otherClass.someMethod()
// ...some other code that depends on temp
}
}
Now, if methodToBeTested was designed to accept an instance of AnotherClass I could easily create a mock of AnotherClass and tell Mockito to return a value i prefeer when someMethod() is called. However as the above code is designed AFAIK it's not possible to mock AnotherClass and testing this method will depend on what someMethod() returns.
Is there anyway I can test the above code without beeing dependent on what someMethod() returns using Mockito or any other framework?
If available you can use the Spring ReflectionTestUtils setField method:
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html#setField%28java.lang.Object,%20java.lang.String,%20java.lang.Object%29
If not write your own its pretty straight forward using reflection, some info here:
http://www.java2s.com/Code/Java/Reflection/Setprivatefieldvalue.htm
Something like the below, you will need additional error handling to get this to work properly:
public void setField(Object obj, String fieldName, Object value) {
Field f = obj.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
It can then be called like this:
setField(objUnderTest, "fieldToSet", mockObject);
edit
I have just noticed that you are instantiating it inside the method. If that is absolutely necessary then you should follow the possible duplicate link posted by cyroxx.
Although that practice is often a sign of bad design so if you can take it out I would.
Setting the field by reflection as suggested in the other answer will work.
But if you're doing this sort of thing often, I'd recommend PowerMock (in conjunction with Mockito) or JMockIt to achieve this. Both allow you to mock constructors, statics, final fields... in short, just about anything. Very useful with legacy code.
However, when you're writing new code, and your class has a dependency on another class that you want to isolate in this way, you should consider changing the design so that the other object is passed in to your class instead of being instantiated by it. Search for "Dependency injection" and you'll find plenty...
As a quick fix, I usually wrap the call to new:
protected newAnotherClass() { return new AnotherClass(); }
That way, I can overwrite this method from a unit test. It's dirty but it's quick :-)
Here is a JMockit test which does what you want, very simply:
#Test
public void testTheMethodToBeTested(#Mocked final AnotherClass dep)
{
new NonStrictExpectations() {{ dep.someMethod(); result = "whatever"; }};
new ClassToBeTested().methodToBeTested();
new Verifications() {{
// verify other calls to `dep`, if applicable...
}};
}
I have to throw an IOException using Mockito for a method, which is reading an input stream like given below. Is there any way to do it?
public void someMethod() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
firstLine = in.readLine();
} catch(IOException ioException) {
// Do something
}
...
}
I tried mocking like
BufferedReader buffReader = Mockito.mock(BufferedReader.class);
Mockito.doThrow(new IOException()).when(buffReader).readLine();
but didn't work out :(
You're mocking a BufferedReader, but your method doesn't use your mock. It uses its own, new BufferedReader. You need to be able to inject your mock into the method.
It seems that inputStream is a field of the class containing this method. So you could mock the inputStream instead and make it throw an IOException when its read() method is called (by the InputStreamReader).
You can't mock BufferedReader here since it's being created inside the method.
Try mocking inputStream and throwing the exception from InputStream.read() instead.
The way that I would recommend is to have an extra class that looks after the creation of the BufferedReader. This class has just one method, with no actual logic in it, so it doesn't need any unit tests.
public class BufferedReaderFactory{
public BufferedReader makeBufferedReader(InputStream input) throws IOException{
return new BufferedReader(new InputStreamReader(input));
}
}
Now, add a private field of type BufferedReaderFactory to the class that you're testing, along with a means of injecting it - either a setter method or an alternate constructor. In the standard constructor for your class, instantiate a BufferedReaderFactory and set the field accordingly. In your someMethod(), call the makeBufferedReader() method on the field, instead of using new.
Your class is much more testable; because now, you can write a test that injects a mocked BufferedReaderFactory to the object that you're testing, before calling someMethod(). On that mock, you can stub the makeBufferedReader method to throw the exception that you want.
Please add a comment if you want me to go into more detail on any of the steps above. You might also like to read my post on mocking object creation on the Mockito wiki; which is closely related to this.
But the most important message is that making your classes testable is really important, and you will reap the benefits of doing so many times over.