How to test that an instance method is called with certain arguments? - java

I'm building a simple RESTful app (using Spark Java, although this question is more general).
The Handler below is called when the /users index route is requested. It just queries for all users and renders an HTML template (using Velocity, but again this question is more general).
package com.example.api;
import java.util.*;
import spark.Request;
import spark.ModelAndView;
import spark.template.velocity.VelocityTemplateEngine;
public class UsersIndexHandler {
private Map<String, Object> locals;
private UserDao userDao;
public UsersIndexHandler(UserDao userDao) {
this.locals = new HashMap<>();
this.userDao = userDao;
}
public String execute(Request req, boolean formatAsHtml) {
// Set locals so they are available in the view
locals.put("users", userDao.all());
// Render the view
String body = new VelocityTemplateEngine().render(new ModelAndView(locals, "views/users/index.vm"))
return body;
}
}
I'm trying to write a basic Junit test for this scenario. I could test the contents of the String that's returned, but I have two issues with that -
The HTML for the page could be quite long, so it doesn't feel practical to do a direct comparison of the actual result with an expected test string
The content of view should be tested in a view test.
What's the "right" (generally accepted) way to test this? Is there a way to set expectations on VelocityTemplateEngine() so we know that render() is called correctly AND with correct arguments?
Or should I focus on just testing the locals Map object, even though I'd have to expose that to access it during tests?
Thanks!

I am in line with the views that Tom has mentioned in the comment but if still,
you want to follow this pattern, Powermockito (and plain Powermock also) have a way to do this. I will Just post an example here
Employee mockEmployeeObject = mock(Employee.class);
PowerMockito.whenNew(Employee.class)
.withAnyArguments().thenReturn(mockEmployeeObject);
verify(mockEmployeeObject, times(1)).someMethod();
Powermockito.whenNew(..) lets us return our mocked object when any new object of that class is created, since you want to verify the method parameters, it works well for you. You can add the verify that you need I just posted an example.
Hope this helps!
Good luck!

Related

Unit Test class that uses only local variables for composition

I am writing app that uses various REST api endpoints with very similar properties. Only difference is in endpoint adress and payload. Headers, method and other stuff remain the same. That is why I created class to communicate with my remote host, it is called RestApiCommunicator that has method generateRequestAndCallEndpoint(List payload) that wraps payload with all required stuff needed to perform rest call.
Than, I have various classes that only call this communicator class with proper endpoint suffix an its resources.
Everything is working fine but I want to unit test all of those classes. I was trying to figure out how to do that by reading a lot of SO questions but they are rather complicated cases, my is very simple.
I am trying to figure out a proper way to unit test a class that looks like this one:
class MyRestClient {
public void useRestApi(List<MyResources> myResources) {
RestApiCommunicator restApiCommunicator = new RestApiCommunicator ("/some/endpoint");
restApiCommunicator.generateRequestAndCallEndpoint(myResources);
}
}
I want to test if communicator was created with proper enpoint adress and if generateRequestAndCallEndpoint was called exacly once with my sample payload.
Only thing that comes to my mind is that make restApiCommunicator a field, create setter for this field and mock it in Unit tests. But this seems to me as rather dirty solution and I wouldn't like to modify my code to allow tests.
Maybe you can point me in some direction where I could have this class tested using some good pattern.
(ps. If that matters - this is a Spring Boot app)
You could provide a factory for the communicator
class MyRestClient {
private RestApiCommunicatorFactory factory = ...
public void useRestApi(List<MyResources> myResources) {
factory.getCommunicator("/some/endpoint")
.generateRequestAndCallEndpoint(myResources);
}
In your unit test, you provide a mock of the factory, which returns mock communicators. The specific language for that depends on your mocking library of choice.
One way to do exactly what you ask (ie, "to test if communicator was created with proper enpoint adress and if generateRequestAndCallEndpoint was called exactly once with my sample payload") is to mock it using JMockit:
public final class MyRestClientTest {
#Tested MyRestClient restClient;
#Mocked RestApiCommunicator restApi;
#Test
public void verifyUseOfRestApi() {
List<MyResource> resources = asList(new MyResource("a"), new MyResource("b"));
restClient.useRestApi(resources);
new Verifications() {{
new RestApiCommunicator("/some/endpoint");
restApi.generateRequestAndCallEndpoint(resources); times = 1;
}};
}
}

Should I repeat code in actual class in tests

I want to test that a specific method produces the expected result, but to do that I need to manipulate the input in the test as well.
class ToTest {
public String produceResponse(String input) {
// ....
encryptedIds = encryptIds(input)
output = doStuff(input, encryptedIds)
}
public encryptIds(input) {
....
}
}
In my test I need to check that produceResponse actually produces the expected response.
in order to do that I have to encrypt the ids in the input.
My question is: should I rewrite encryptIds in the test (so that I would have more controller on the result) or should I call encryptIds from the class itself.
Is there a better approach to solve this? I don't like that in my test I know what happens in the specific flow.
If I understand correctly, you would like to test produceResponse() with known encryptedIds as input.
You could do that without refactoring the code, but it would probably be a good idea to refactor it, so that's what I'm going to explain:
class ToTest {
private IdEncryptor encryptor;
public ToTest(IdEncryptor encryptor) {
this.encryptor = encryptor;
}
public String produceResponse(String input) {
String[] encryptedIds = encryptor.encryptIds(input);
return doStuff(input, encryptedIds);
}
}
Now you can unit-test IdEncryptor to test that it produces correct encrypted IDs based on a String input.
And to test the ToTest class, you can mock the IdEncryptor so that whatever the input it receives, it produces the encryptedIds you desire. For example with mockito:
IdEncryptor mockEncryptor = mock(IdEncryptor.class);
when(mockEncryptor.encryptIds(any(String.class)).thenReturn(new String[] {"a", "b"});
ToTest toTest = new ToTest(mockEncryptor);
String response = toTest.produceResponse("input");
// expect that the response is what you expect given "a", "b" as input of doStuff()
Never copy any production code into the unit test as it will get outdated at some point.
If both methods are public, they are part of the public API, so:
you should first unit test the correct behavior of the encryptIds(String) method
then unit test the produceResponse(String) method which will internally use the already tested encryptIds(String) method
If encryptIds(String) would not be part of the public API:
then it is internal implementation and helper method which is not unit testable
produceResponse(String) is then responsible for encryption as a side-effect:
you can still test it if you mark it package private (no modifier)
you can also change the implementation of the encryptIds(String) only for testing purposes
Is encrypting id's something that is integral to your system or not? As it stands this class takes some input and produces some output and as far as your test is concerned this is what's important, no more, no less.
What is the impact of not performing the encryption? If your doStuff method will just fail if it doesn't happen then it is an internal detail to your class-under-test and I wouldn't have the tests care about it at all. If it's a step that absolutely must be performed then I would refactor the code to verify that it absolutely has happened, maybe using a mock as #jb-nizet answered.
As for the general case of duplicating production code in tests, as #Crazyjavahacking stated you should not do this, but I have no issue with using production code from a test- maybe not at a unit level but definitely the higher up the system I go, e.g. when testing writing to a DB I will use the reading code to verify it's happened correctly, but will also have independent tests to verify the reading path as well

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;

Conditional generation of method bodies to satisfy large interfaces in Java

The Java OpenGL GL interface contains about 2000 methods, for debugging purposes I would like to wrap an instance and delegate calls to it while doing some logging. The logging code can be pushed to the same method in each case, so the task of writing out the method implementations looks like it could be automated. An example of what I am trying to do:
import javax.media.opengl.GL;
public class GLErrorLogger implements GL {
private final GL backing;
public GLErrorLogger(GL delegateToMe) {
backing = delegateToMe;
}
private void checkErrorCode() {
// Log frame and thread details depending on gl state
}
/**
* Example of a method
*/
#Override
public int glGenLists(int arg0) {
checkErrorCode();
int retVal = backing.glGenLists(arg0);
checkErrorCode();
return retVal;
}
// rest of methods here...
}
In other words copy the method name and parameters (minus their types) into a call on the backing object, surround with calls to the logging method, and if there is a return type then assign the result to a variable of this type and return it at the end of the method.
I looked at creating a one shot eclipse code template to autogenerate the methods, but there wasn't an immediately obvious way to do pattern matching on the return type. Can anyone suggest a way to do this in Eclipse or any of its code generation tools to save me pulling out the regex toolkit?
You might want to use an Aspect to create the necessary bytecode for you instead of producing all the source code. Take a look at the Traceing Aspect example here: Traceing Aspect Example.
As an Alternative, you can create a Java Dynamic Proxy, if you do not want to use AspectJ as Thrid party Library. Please refer to Dynamic Proxy Tutorial
Use JDK proxies as suggested, or: use a Mock Framework like EasyMock or Mockito.
GL mock = EasyMock.createMock(GL.class);
EasyMock.expect(mock.someMethod()).andReturn(someValue);
// or, if you need to do more computing:
EasyMock.expect(mock.someOtherMethod()).andAnswer(new IAnswer<String>() {
public String answer() throws Throwable {
return "some value you calculate here";
}
});
EasyMock.replay(mock);
now you can use the mock Object for all methods you configured.
See the EasyMock readme for more info.

How can I get an object out of the model in the controller with Spring MVC 3?

I have a controller with a method that handles incoming GET data, stores some things in the model, and then redirects to another page that deals with these objects.
I can't seem to find any good way of getting the object stored in the first method back out of the model to use in the second method. How can I do this?
Here's the top of the controller:
#Controller
#RequestMapping("/reviews")
#SessionAttributes({"review", "externalReview"})
public class ReviewController {
// [SNIP]
}
Here's the code that adds the objects I'm after to the model:
#RequestMapping(value="/new", params="UName", method=RequestMethod.GET)
public String newFormFromExternal(#ModelAttribute("externalReview") ExternalReview externalReview, Model model) throws IncompleteExternalException {
// Convert the inbound external
Review fromExternal = ExternalReviewUtil.reviewFromExternalReview(externalReview, externalDAO);
// Add the externalReview to the session so we can look to see if we got a reviewee on the way in
model.addAttribute("externalReview", externalReview);
model.addAttribute("review", fromExternal);
return "redirect:/reviews/newFromExternal";
}
You are in luck.
If you are using or have ability to update to the newly released Spring 3.1, you can make use of the newly scoped Flash variables.
http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/mvc.html#mvc-flash-attributes
If you can't use 3.1, you probably can implement the solution yourself. Essentially you want to capture the model object required to be present in the redirect, put in the session, and remove it once it is retrieved to keep your session from bloating.
Currently, I'm just getting a Map of the model, getting the object I want out by it's key (the String name), and then casting it to the object it really is (rather than just Object).
Here's the code:
#RequestMapping(value="/newFromExternal", method=RequestMethod.GET)
public String newExternalForm(Model model) {
// Get the review from the model
Review review = (Review) model.asMap().get("review");
/*** Do stuff with the review from the model ****/
return "reviews/newFromPacs";
}
This way works, but it seems hacky and clunky. Is this really the only way?
One possible solution is to use #ModelAttribute, though it's quite ugly since you'll need to disable databinding for that attribute (for security):
#RequestMapping(value="/newFromExternal", method=RequestMethod.GET)
public String newExternalForm(#ModelAttribute Review review) {
...
}
#InitBinder("review")
public void disableReviewBinding(WebDataBinder b) {
b.setAllowedFields();
}

Categories

Resources