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

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.

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.

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.

Using mocked method argument to mock next steps

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.

Clarification in Java Code Testing

I have started reading the Spring in Action book.
I have no knowledge of JUnit which I think my doubt is about.
There is a code fragment where the author refers to and says that it is difficult to test:
package com.springinaction.knights;
public classDamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
quest = new RescueDamselQuest();
}
public voidembarkOnQuest() throwsQuestException {
quest.embark();
}
}
The author says that:
It’d be terribly difficult to write a unit test for DamselRescuingKnight. In such a test, you’d like to be able to assert that the quest’s embark() method is called when the knight’s embarkOnQuest() is called. But there’s no clear way to accomplish that here. Unfortunately, DamselRescuingKnight will remain untested.
What does the author mean by this?
Why is the code difficult to test here?
My initial thought is that it is difficult to test because the "RescureDamselQuest" object is initialized in the constructor. This makes it difficult to for example insert a mock object. A mock object would help you test that the embark() method is called on the "RescueDamselQuest" object.
A better way to solve this can be to either include a parameter in the constructor (usually I prefer this method):
public DamselRescuingKnight(RescueDamselQuest quest){
this.quest = quest;
}
Or add a setter:
public void setDamselRescuingKnight(RescueDamselQuest quest){
this.quest = quest;
}
A common example I give is consider that you want to open a file, parse it, and get a data class out. Most will do something like:
Data openAndParse(String filename) {
...openFile
...parse
}
By doing it this way, the file open methodology and parse is highly coupled and difficult to test. If you have a problem in open and parse is it with the parse or the open?
By writing JUnit test, you are forced, for simplicity sake, to do something like...
BufferedReader openFile(String filename) {
...open file and return reader
}
Data parse(BufferedReader input) {
...parse and return data
}
JUnit leads us to a more cohesive solution. We write JUnit test simply by creating a string, constructing a StringReader, and then a BufferedReader. Well guess what? Very similarly we can now use parse to accept input from a variety of sources not just the file.
It's difficult to test because the quest implementation cannot be swapped out. Without byte code modification there's no trivial way to see if embark is called.
If you could set the quest implementation in a constructor or setter you could pass in an implementation that can spy on the call to embark.
One need to increase accessibility of fields and method of class to test. For example if one is testing a method which is package-private (default) then test cases which are generally in different package will not able to test this method. Therefore it is advised to to change in accessibility of fields to test the method. DamselRescuingKnight class can be tested which is not using DI by modifying the accessibility of RescueDamselQuest field from private to default. Then writing test case using mockito. Here is code for test case
#Test
public void knightShouldEmbarkOnQuest() throws QuestException {
DamselRescuingKnight knight = new DamselRescuingKnight();
RescueDamselQuest quest = mock(RescueDamselQuest.class);
knight.quest = quest;
knight.embarkOnQuest();
verify(quest, times(1)).embark();
}
And line which was changed in DamselRescuingKnight class to remove private accessibility
RescueDamselQuest quest;

How to design a private/final method available for mocking?

This is the class that I have to test:
public class Downloader {
public String download(String uri) {
HttpClient client = this.getHttpClient();
client.setURI(uri);
return client.get();
}
private HttpClient getHttpClient() {
HttpClient client = new HttpClient();
// + some config
return client;
}
}
Very simple. Now I want to test its behavior when getHttpClient() throws an exception. However, I can't mock this method, since it is private. What is a common practice in such a situation?
I would make the HTTPClient a field of the class that is set up on construction (via a interface). Then you have the ability to create a mock HTTPClient that can throw an exception during the test if you want, e.g.:
public class Downloader {
private IHTTPClient client;
public Downloader(IHTTPClient client) {
this.client = client;
}
public String download(String uri) {
this.initialiseHttpClient();
client.setURI(uri);
return client.get();
}
private HttpClient initialiseHttpClient() {
// + some config
}
}
Then call the constructor with a real HTTPClient in production code and a Mock in the test code. You may need to create a wrapper for HTTPClient for the real code.
If you're trying to test private methods, I think something's not quite right.
You should be testing your class against its contract. The private methods are implementation-dependent, and so (in a sense) it doesn't matter what they do. You should be checking that your public methods work as expected in both functioning and non-functioning scenarios, and reflect this as appropriate back to the client (in this case, your test class).
You may need to substitute some functionality into your class for test purposes (e.g. substitute in a broken JDBC connection etc.) In that scenario I would investigate mocking and dependency injection.
It does sound a little cheesy but I generally make methods like this public and add conspicuous javadocs saying "this method is exposed public only for testing".
You can also use package-only access by having the xunit/mock etc. in the same package.
I tend to prefer using simple solutions like this as opposed to more complex and hard-to-debug techniques like AOP-style code injection.
You could make getHttpClient() protected and subclass it in the test to return what you want, so you'd have something like this in your tests:
public class TestableDownloader extends Downloader {
protected HttpClient getHttpClient() {
throw new Exception();
}
}
This isn't ideal though, you'd be better having a different design which didn't require you to test private methods (perhaps using dependency injection to provide a factory or something).
Private methods are not supposed to get a unit test. You are only supposed to unit test public methods. How a public method is organized internally does not matter to unit testing. A unit is not equal to a method. It is equal to a behavior that is possibly using more than one method to do its job.
Mocking is also a useless thing to do. If you have to mock something, your method is really integrating functions. Your code is needing refactoring to make it only do one thing and then a wrapper method calls it and the to be mocked object to integrate it.
Unit testing is something that sounds like you should do but in reality is a waste of effort that you are better to use in coding your application. Unit testing is no guarantee of better code quality and maybe it is making it worse because you are not spending enough time on your real code.

Categories

Resources