Using mocked method argument to mock next steps - java

I have a method in my code that looks something like this:
action.onResult(new Handler<MyClass>() {
#Override
public MyClass handle() { // Do something here }
}
}
I want to be able to mock it (using Mockito). Something like this:
when(mockedAction.onResult(any(Handler.class))).thenReturn(firstArg.handle());
Meaning, I want to call the handle method of the argument that's sent to the method onResult. I can't mock the handler because it uses inner methods of the calling class (I thought about using a private class but haven't reached a good enough solution)
Motivation: This is an asynchronous callback mechanism that's used in a synchronous area. I want to mock the call to the handler itself in order to continue the flow synchronously in the code.

OK, UNTESTED but here is a possible use of ArgumentCaptor for this scenario:
final ArgumentCaptor<Handler> captor = ArgumentCaptor.forClass(Handler.class);
when(mock.onResult(captor.capture())).thenReturn(captor.getValue().handle());
Not sure however whether the captor has the "time" to initialize here.

Related

Mock method with Consumer

I want to mock repository.actionOnFile(String path, Consumer<InputStream> action) in this source:
#Autowired
private FileRepositoryService repository;
public Document getDocument(URL url) {
MutableObject<Document> obj = new MutableObject<>();
Consumer<InputStream> actionOnFile = inputStream -> obj.setValue(getDocument(inputStream));
try {
repository.actionOnFile(url.toExternalForm(), actionOnFile);
} catch (S3FileRepositoryException e) {
throw e.getCause();
}
return obj.getValue();
}
The problem is that the second argument is a lambda expression.
How to mock it with mockito, I need to pass to the accept method the input stream to test it?
I found solution!
doAnswer(ans -> {
Consumer<InputStream> callback = ans.getArgument(1, Consumer.class);
InputStream stream = new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8));
callback.accept(stream);
return null;
}).when(repository).actionOnFile(eq("any"), any(Consumer.class));
If you only want to mock the Function argument then the following would work:
Mockito.when(convertStringtoInt(Mockito.any(String.class), Mockito.any(Consumer.class))).then[...]
How to mock it with mockito, I need to pass in accept method test
input stream?
In your case, you want to test the getDocument() method.
So what you need to mock is the dependency of the class under test :
that is the repository field.
actionOnFile.add() more specifically should be mocked.
According to your code, either the method should throw S3FileRepositoryException or it provokes a side effect not visible in the code.
In the exception scenario, you should write something as :
 Mockito.when(fileRepositoryServiceMock.actionOnFile(url.toExternalForm(), actionOnFile)).thenThrow(new S3FileRepositoryException(cause));
And in the successfull, you should just verify that the method is invoked :
 Mockito.verify(fileRepositoryServiceMock).actionOnFile(url.toExternalForm(), actionOnFile));
Mocking a Consumer is really not a big deal.
It is a interface, you can mock any interface with Mockito.
The real issue is actually the Consumer makes not part of the API of the tested method.
It is a local variable.
Besides, it relies on an inputStream field that is not show in the code.
You cannot and have not to mock internal things.
Note that it also relies on a overloaded getDocument() method that is not mocked. So you would need to provide a consistent InputStream if you want to getDocument() that accepts a inputStream doesn't throw an exception.
Long story short : I think that you should either rethink your design to extract the depending processings in another class or write an integration test.

How can I "intercept" a method call for a test?

I have a class like so:
class A {
public static void makeCall() {
URL url = "www.google.com";
InputStream result = url.openStream();
//Do more stuff
}
}
And I want to write a unit test for it. What I want to happen is sort of "intercept" the call to openStream() so that I can run the static method makeCall() and just return some sort of hard coded JSON back, instead of actually making the call. I haven't been able to figure out how to mock this up, or if it's even possible.
I am looking for the same behavior as Angular's $httpBackend, any ideas or suggestions?
You shouldn't need to mock method member variables. For better design make the url a parameter in the method.
public static void makeCall(URL url){
Then in your test pass in a mock.
This also allows for more flexibility and possible code reuse in the future.

Junit testing method which returns nothing and has service call to other system

I have a method which does following.
public void callService(SomeObject someObject) {
// call helper class method and create a request XML
// scrub this XML using a local method and persist it in MongoDB
// call a 3rd party service using HTTP POST
// Recieve the response
// Persist the response in MongoDB and set in in somObject
// return
}
Now as part of development we have to write unit test cases for this method. I am new to Junit testing as well as mock objects. but when I googled and looked at the some other similar questions I understood that testing void method is little bit different than normal methods and I think my above method which special in some more way as I am clueless as to what and how to test for this method.
Can someone please give me pointer or any reference as to how I can unit test this method using Junit.
You'd probably want to use mocks to stand in for your Mongo connection and the third party service. It's easiest to use an existing mock framework, but this is the general concept.
Pretend that you post to this third party service by constructing a StuffToPost object and passing it to the post method on your ThirdPartyPoster. Then you can create a mock object as follows:
public class MockThirdPartyPoster implements ThirdPartyPoster {
private int count = 0;
private StuffToPost stuffToPost;
#Override
public void post(StuffToPost stuffToPost) {
this.count++;
this.stuffToPost = stuffToPost;
}
public int getCount() {
return count;
}
public StuffToPost getStuffToPost() {
return stuffToPost;
}
}
In your test, you'd construct this MockThirdPartyPoster and pass it to thingToTest.setThirdPartyPoster, then call your method. Once the method finishes executing, you can call getCount() on the mock to make sure that you POSTed once and only once, and call getStuffToPost() to examine the StuffToPost object and make sure that it is correct. You'd do something similar for Mongo persistence as well.
That calls for a lot of boilerplate; mock frameworks like Mockito or EasyMock exist to solve that problem.

Mocking a Spy method with Mockito

I am writing a unit test for a FizzConfigurator class that looks like:
public class FizzConfigurator {
public void doFoo(String msg) {
doWidget(msg, Config.ALWAYS);
}
public void doBar(String msg) {
doWidget(msg, Config.NEVER);
}
public void doBuzz(String msg) {
doWidget(msg, Config.SOMETIMES);
}
public void doWidget(String msg, Config cfg) {
// Does a bunch of stuff and hits a database.
}
}
I'd like to write a simple unit test that stubs the doWidget(String,Config) method (so that it doesn't actually fire and hit the database), but that allows me to verify that calling doBuzz(String) ends up executing doWidget. Mockito seems like the right tool for the job here.
public class FizzConfiguratorTest {
#Test
public void callingDoBuzzAlsoCallsDoWidget() {
FizzConfigurator fixture = Mockito.spy(new FizzConfigurator());
Mockito.when(fixture.doWidget(Mockito.anyString(), Config.ALWAYS)).
thenThrow(new RuntimeException());
try {
fixture.doBuzz("This should throw.");
// We should never get here. Calling doBuzz should invoke our
// stubbed doWidget, which throws an exception.
Assert.fail();
} catch(RuntimeException rte) {
return; // Test passed.
}
}
}
This seems like a good gameplan (to me at least). But when I actually go to code it up, I get the following compiler error on the 2nd line inside the test method (the Mockito.when(...) line:
The method when(T) in the type Mockito is not applicable for the arguments (void)
I see that Mockito can't mock a method that returns void. So I ask:
Am I approaching this test setup correctly? Or is there a better, Mockito-recommended, way of testing that doBuzz calls doWidget under the hood? And
What can I do about mocking/stubbing doWidget as it is the most critical method of my entire FizzConfigurator class?
I wouldn't use exceptions to test that, but verifications. And another problem is that you can't use when() with methods returning void.
Here's how I would do it:
FizzConfigurator fixture = Mockito.spy(new FizzConfigurator());
doNothing().when(fixture).doWidget(Mockito.anyString(), Mockito.<Config>any()));
fixture.doBuzz("some string");
Mockito.verify(fixture).doWidget("some string", Config.SOMETIMES);
This isn't a direct answer to the question, but I ran across it when trying to troubleshoot my problem and haven't since found a more relevant question.
If you're trying to stub/mock an object marked as Spy, Mockito only picks up the stubs if they're created using the do...when convention as hinted at by JB Nizet:
doReturn(Set.of(...)).when(mySpy).getSomething(...);
It wasn't being picked up by:
when(mySpy.getSomething(...)).thenReturn(Set.of(...));
Which matches the comment in MockHandlerImpl::handle:
// stubbing voids with doThrow() or doAnswer() style
This is a clear sign that doWidget method should belong to another class which FizzConfigurator would depend on.
In your test, this new dependency would be a mock, and you could easily verify if its method was called with verify.
In my case, for the method I was trying to stub, I was passing in incorrect matchers.
My method signature (for the super class method I was trying to stub): String, Object.
I was passing in:
myMethod("string", Mockito.nullable(ClassType.class)) and getting:
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
When using a matcher in another parameter, we also need to use one for the string:
myMethod(eq("string"), Mockito.nullable(ClassType.class))
Hope this helps!

UnitTest: how to test if an Listener's update has been called

What is the simplest way to make sure the listener's update has even been called ?
Update: I am testing the Listener (not the Subject) and once update is called, the test pass.
d.addServiceComponentChangeListener(new ServiceComponentChangeListener() {
//In the Unittest, I want to make sure this has been called
public void notifyChange(ServiceComponentChangeEvent event) {
System.out.println("#notifyChange");
}
});
Even if the listener does not implement an interface, you can still create a mock for it using something like Mockito. Using runtime code insertion, inspection of the class to be mocked, and purple pixie dust, it can impersonate other classes. At my company most unit tests use either Mockito (the newer ones) or EasyMock (the older ones) so we're sure we're testing JUST the one class.
I question your statement "Update: I am testing the Listener (not the Subject)", though. If your test is verifying the listener gets called, you're testing the thing that's supposed to call the listener, not listener itself. So which is it?
If the listener implements the interface you can make a mock class that implements the listener. Then you can design this mock to fit your testing. If it does not implement an interface, as long as the listeners class is not final, you could extend it.
I would test it by replace the call System.out or whatever that section should really do with an interface that be later mocked and use behavior verification to make sure it was called. So...
public class d
{
private MessageDisplayer m_UserDisplay;
public d()
{
m_UserDisplay = new DisplaySystemOut()
}
public d(MessageDisplayer AllowsSensing)
{
m_UserDisplay = AllowsSensing;
}
//blah blah blah....
d.addServiceComponentChangeListener(new ServiceComponentChangeListener()
{
public void notifyChange(ServiceComponentChangeEvent event) {
m_UserDisplay.DisplayMessage("#notifyChange");
}
});
}
Now you can mock MessageDisplayer in your test and make sure it is called and that the parameter was equal to "#notifyChange"

Categories

Resources