JUnit assert against play.mvc.Result content? - junit

How does one assert against content within the body of a Play! JSON action Result value? I'm returning a new (or even null) JSON ObjectNode from an action and attempting to assert against it within the result from a unit test, but don't see the value (null or otherwise) in the response.wrappedResult.body.
For example, in my action, if I return a null JSON Object Node,
ObjectNode response = null;
return ok(response);
or if I return a test value,
ObjectNode response = Json.newObject();
response.put("testKey", "testValue");
return ok(response);
and then I write a test against the result,
#Test
public void MyTest() {
Result result = MyController.myAction();
// assert against null or specified values here
}
and I then explore the entire object graph,
result.wrappedResult.body
I don't see anything that looks like my specified results to assert against.
Any ideas?
Thanks!

Take a look at Testing your controllers in the Play docs on Java testing for an example of how to correctly call your actions and test Result content.
#Test
public void callIndex() {
Result result = callAction(
controllers.routes.ref.Application.index("Kiki")
);
assertThat(status(result)).isEqualTo(OK);
assertThat(contentType(result)).isEqualTo("text/html");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(contentAsString(result)).contains("Hello Kiki");
}
Play does some clever stuff when it calls actions so you need to wrap your call in callAction. You won't get the same result if you call the action method directly.

Related

How to write Junit test case for postAbs method of WebClient in Vert.x?

I recently developed few Verticles from which I needed to make external API calls. To optimize the code, I moved code of calling APIs to one common Helper class. I am also passing Vertx instance from Verticle to Helper class. I am now trying to write Junit test case for the Helper class which is looking like below working code.
public class ServiceExecutionHelper{
public Promise<String> executeService(String requestURI, JsonObject input, MultiMap headers, Vertx vertx){
Promise<String> promise = Promise.promise();
WebClient client = WebClient.create(vertx);
client.postAbs(requestURI).timeout(60000).putHeaders(headers)
.sendJsonObject(input, ar -> {
if (ar.succeeded()) {
HttpResponse<Buffer> response = ar.result();
JsonObject serviceRespone = new JsonObject(response.bodyAsString());
JsonArray responseData = serviceRespone.getJsonArray("response_data");
if(responseData != null){
promise.complete("promise_completed");
}else{
promise.fail("promise_failed");
}
}
}
return promise;
}
}
Can anyone please guide how could I write test case for above code?
There are a million ways to do this depending on what exactly you need to test.
Here is one suggestion using junit5 and okhttp's MockWebServer. There are a lot of other conceivable alternatives.
The test verifies:
That you send a POST request using the payload contained in the input parameter.
That your implementation can handle a json response from the webserver.
That your implementation sends exactly one request to the webserver.
That your code completes the Promise if the server's response contains the key "promise_completed"
#ExtendWith(VertxExtension.class)
#Slf4j
public class ServiceExecutionHelperTest {
private ServiceExecutionHelper sut;
private MockWebServer mockWebServer;
#BeforeEach
public void setUp() {
sut = new ServiceExecutionHelper();
mockWebServer = new MockWebServer();
}
#Test
public void testExecuteService(final Vertx vertx, final VertxTestContext testContext) throws InterruptedException {
// given
final JsonObject requestPayload = new JsonObject().put("request", new JsonArray("[]"));
final JsonObject serverResponsePayload = new JsonObject().put("response_data", new JsonArray("[]"));
mockWebServer.enqueue(new MockResponse()
.setBody(serverResponsePayload.encode())
.setResponseCode(200)
.setHeader("content-type", "application/json"));
// when
final Promise<String> stringPromise =
sut.executeService(
mockWebServer.url("/").toString(),
requestPayload,
MultiMap.caseInsensitiveMultiMap(),
vertx);
// then
final RecordedRequest recordedRequest = mockWebServer.takeRequest();
assertEquals("POST", recordedRequest.getMethod());
assertEquals("[text={\"request\":[]}]", recordedRequest.getBody().toString());
assertEquals(1, mockWebServer.getRequestCount());
testContext.assertComplete(stringPromise.future())
.map(val -> {
assertEquals("promise_completed", val);
testContext.completeNow();
return val;
})
.onComplete(onComplete -> {
assertTrue(onComplete.succeeded());
log.info("done");
})
.onFailure(onError -> Assertions.fail());
}
}
Some words from a TDD point of view
Before you start writing tests (and your actual code too, if you ask me), you should clarify your functional and technical requirements.
These should be the basis for your tests. And the tests should be a starting point to implement your code against.
So I cannot promise you that this example is a correct test for your use case. It compiles and and runs. But it should be verified and extended following your actual requirements.
Concerning test coverage
To keep this answer short and concise, I did not write the test to cover all possible branches. The case where the server responds without response_data (i.e. the else branch of your if-clause, where the Promise fails) is not tested.
To cover that case, a second test or the usage of a parameterized test would be necessary.

Get json content of request and response on annotated Spring Controller

I want to build a library that will save the Json content of request and response on annotated Spring controller.
So i've build my own annotation #Foo and put it on some controllers:
#Foo
#RequestMapping(method = RequestMethod.POST, value = "/doSomeThing", produces = {
MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_XML_VALUE,
MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<T> doSomething(/*some parameters*/) {
T t = doSomeJob(T.class);
return new ResponseEntity<T>(t, HttpStatus.OK);
}
I have no guarantee that request and response are in Contrellor's parameters!
And i'm catching the call on any Controller having that annotation within an #AfterReturning AOP pointcut.
#Component
#Aspect
public class XYInterceptor
#AfterReturning(
pointcut = "execution(#my.annotation.Foo)")
public void doSomethingWithJsonContent(JoinPoint joinPoint) throws Throwable {
//How can i get json value of request and response here?
}
How can I get request and response content formatted in json (such as it is send/returned to the client) ?
Thanx for your help!
Well, you need request and response somehow accessible from your controller method, either via an injected class member, method parameter or method return value. It has got to be somewhere. Because you did not explain where you intend to get it from, I can just post a general answer showing how to determine method arguments and return value from an #AfterReturning advice. If you update the question with more detailed information, I can also update the answer accordingly.
My pointcut (the commented-out one also works, choose your favourite one) binds the return value to a parameter and just assumes that both request and response are of String type. Feel free to replace by your favourite. Furthermore, you can bind a parameter from your intercepted method (no matter where it is in the signature) to a typed advice method parameter if you know that the parameter exists and also know its (super) type. This way you can get rid of the slow and ugly loop over getArgs().
//#AfterReturning(pointcut = "execution(#my.annotation.Foo * *(..))", returning = "response")
#AfterReturning(pointcut = "#annotation(my.annotation.Foo)", returning = "response")
public void interceptRequest(String response, JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
for (Object arg : thisJoinPoint.getArgs()) {
if (arg instanceof String)
System.out.println(" request = " + arg);
}
System.out.println(" response = " + response);
}

Struts2 TDD - Testing chaining - how to prevent dispatcher from doing the chain?

I'm running a JUnit test - testing an action that chains.
We have a large internal testing framework (inherits from StrutsTestCase) that sets up everything for an action to work during a test but when chaining to a new action - the new (chained) action isn't setup correct and internal code runs into NULLs.
I believe the test should only test for the correct result from the action call and should not test the chained action.
My Q: I'm looking for a way to disable chaining while testing. Can the Dispatcher created in StrutsTestCase.setUp() be configured to handle chaining differently (eg. do nothing)?
Wish I could avoid chaining but that's the way it's done here.
EDIT - Here is code:
Action:
#Action(value = SUBMIT, results = {
#Result(name = SUCCESS, type = "chain", params = { "actionName", "myActionName", "namespace", "/myNameSpace" }) })
public String submitForm() throws IllegalAccessException, InvocationTargetException, IOException {
return SUCCESS;
}
Test:
#Test
public void testStuff() throws Exception {
setupAction();
prepareForValidUser();
this.actionUnderTest.getModel().setUpSomeStuff(someSetupValue);
final String result = this.proxy.execute();
assertEquals("Result not the expected result", SUCCESS, result);
}
The test relies heavily on a nice testing framework; proxy.execute() is what runs the action (com.opensymphony.xwork2.ActionProxy.class).
The solution is to simply call the action method directly instead of relying on the struts framework to execute the action for you.
This:
final String result = this.proxy.execute();
becomes
final String result = this.actionUnderTest.myActionMethod();
This worked well for me! Doing this meant that nothing handled/executed on the result of the action method (eg. no chaining occurred).

Spock mock returns null inside collabolator but not in feature method

I have a problem with Spock Mock() object.
I have a java class I'm trying to test. This class does some ftp stuff I want to mock.
My sample code
class ReceiveDataTest extends Specification{
String downloadPath = 'downloadPath';
String downloadRegex = 'downloadRegex';
SftpUtils sftpUtils = Mock();
ReceiveData receiveData;
def setup(){
sftpUtils.getFileNames(downloadPath,downloadRegex) >> ['file1', 'file2']
receiveData= new ReceiveData()
receiveData.setDownloadPath(downloadPath)
receiveData.setDownloadRegex(downloadRegex)
receiveData.setSftpUtils(sftpUtils);
}
def "test execute"() {
given:
def files = sftpUtils.getFileNames(downloadPath,downloadRegex)
files.each{println it}
when:
receiveData.execute();
then:
1*sftpUtils.getFileNames(downloadPath,downloadRegex)
}
}
public class ReceiveData(){
//fields, setters etc
public void execute() {
List<String> fileNames = sftpUtils.getFileNames(downloadPath, downloadRegex);
for (String name : fileNames) {
//dowload and process logic
}
}
}
Now, inside "test execute" the files.each{} prints what is expected. But when receiveData.execute() is called my sftpUtils are returning null..
Any ideas why?
EDIT
Maybe i didnt state my problem well - that I dont want to just check if getFileNames was called. I need the result to proper check the for loop. If I comment the loop inside execute, the test passes. But since I use the result of the getFilenames() method, I get a NPE execute method reaches the for loop. With mockito I would do something like this
Mockito.when(sftpUtils.getFilenames(downloadPath, downloadRegex)).thenReturn(filenamesList);
receiveData.execute();
Mockito.verify(sftpUtils).getFilenames(downloadPath, downloadRegex);
//this is what I want to test and resides inside for loop
Mockito.verify(sftpUtils).download(downloadPath, filenamesList.get(0));
Mockito.verify(sftpUtils).delete(downloadPath, filenamesList.get(0));
but I cannot use Mockito.verify() inside Spock then block
The main problem is that you did not include the response generator (the >> part) in the expectation (i.e. the "1 * ..." part inside the then: block).
This is explained well in the spock documentation.
http://spockframework.org/spock/docs/1.0/interaction_based_testing.html#_combining_mocking_and_stubbing
https://spock-framework.readthedocs.org/en/latest/interaction_based_testing.html#wheretodeclareinteractions
You shouldn't have to declare your stub in the setup: block. You can just specifiy it once in the then: block -- even though that follows the call to receiveData.execute(). That's part of the magic of spock thanks to Groovy AST transformations. And since (non-shared) fields are reinitialized before each test (more AST based magic), you don't even need setup() in this case.
Another odd thing is that you are both stubbing out sftpUtils.getFilenames() and also calling it from the test code. Mocks and stubs are intended to replace collaborators that are called from the system under test. There's no reason to call the stub from the test driver. So delete the call to getFilenames() from your given block and let the code under test call it instead (as it does).
Groovy lets you simplify calls to Java set and get methods. Look at the initialization of receiveData below. Its okay to use def in Groovy. Let the compiler figure out the data types for you.
Leading to something like:
class ReceiveDataTest extends Specification {
// only use static for constants with spock
static String PATH = 'downloadPath'
static String REGEX = 'downloadRegex'
def mockSftpUtils = Mock(SftpUtils)
def receiveData = new ReceiveData(downloadPath : PATH,
downloadRegex : REGEX,
sftpUtils : mockSftpUtils)
def "execute() calls getFileNames() exactly once"() {
when:
receiveData.execute()
then:
1 * mockSftpUtils.getFileNames(PATH, REGEX) >> ['file1', 'file2']
0 * mockSftpUtils.getFileNames(_,_)
// The second line asserts that getFileNames() is never called
// with any arguments other than PATH and REGEX, aka strict mocking
// Order matters! If you swap the lines, the more specific rule would never match
}
}

Return different values each time from jMockit expectation

I have a unit test where I am mocking java.net.URI class. Further, I am creating a jMockit NonStrictExpectation where I am expecting invocation of URI.getPath() and returning a particular string.
The code being tested invokes URI.getPath() twice, where I need to send a different string each time.
Here is my actual method under test:
public void validateResource() {
// some code
URI uri = new URI(link1.getHref());
String path1 = uri.getPath();
// some more code
uri = new URI(link2.getHref());
String path2 = uri.getPath();
}
Here is the unit test code:
#Mocked URI uri;
#Test
public void testValidateResource() {
new NonStrictExpectations() {
{
// for the first invocation
uri.getPath(); returns("/resourceGroup/1");
// for the second invocation [was hoping this would work]
uri.getPath(); returns("/resource/2");
}
};
myObject.validateResource();
}
Now, I want "/resource/2" to be returned from my expectation when the URI.getPath() is called second time. But it always hits the first expectation and returns "/recourceGroup/1". This is my problem.
How do I make it happen? I can't really use StrictExpectations due to a number of reasons, and will have to stick with NonStrictExpectations.
Seems like you just need to list uri.getPath() once, and use the varargs version of returns...something like this:
uri.getPath(); returns("/resourceGroup/1", "/resourceGroup/2");
This is according to the documentation, anyway...I have not tested it myself.
Multiple consecutive values to return can be recorded for an expectation, by calling the returns(v1, v2, ...) method. Alternatively, the same can be achieved by assigning the result field with a list or array containing the consecutive values.