ramesh027
ramesh027

Reputation: 796

Spring rest junit post with json

I am trying to working with project to create junit test for the spring rest webservice. This work fine with the get method but it did works with the post json as input. Here is the code with get method. if anyone help with rest post json junit testing it will appreciated.

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations=("/spring/application-config.xml"))
public class LoginServiceFacadeTestImpl extends AbstractTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }


    @Test
    public void testSearchProductByNameFound() throws Exception {
        String keyword = "";
        this.mockMvc.perform(get("/perlogin")
            .param("q", keyword)
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$.name").value(keyword));
    }
}

But I am getting the error as follows

Time elapsed: 5.477 sec  <<< FAILURE!
java.lang.AssertionError: Status expected:<200> but was:<404>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
    at org.springframework.test.web.servlet.result.StatusResultMatchers$5.match(StatusResultMatchers.java:549)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:141)
    at com.db.mybank.backend.services.presentation.impl.test.LoginServiceFacadeTestImpl.testSearchProductByNameFound(LoginServiceFacadeTestImpl.java:104)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103)
    at $Proxy0.invoke(Unknown Source)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69)

Here is my controller class

package com.backend.controller;

@Controller
@RequestMapping("/")
public class JSONController {

    @Autowired
    private SessionManager sessionManager;

    public JSONController() {
    }   

    @RequestMapping(value = "/perlogin", method = RequestMethod.POST)
    public @ResponseBody
    ValDataVo preLogin(HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse) {
        addDefaultResponseHeaders(httpServletResponse);     
        sessionManager.setHttpSession(httpServletRequest.getSession());
        logger.info("***login session*****::"+httpServletRequest.getSession().getId());

        return resultData;
    }
}

Here is my dispatcher servlet

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context"  xmlns:p="http://www.springframework.org/schema/p" 
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
       default-autowire="byName">

    <mvc:annotation-driven/>     
    <context:component-scan base-package="com.backend.controller" />

</beans>

Upvotes: 6

Views: 9840

Answers (2)

Dan Hargis
Dan Hargis

Reputation: 457

So the component scanner is picking up your Controller.

See if this works for you:

My approach uses Jackson to JSon encode an object and POST's the Rest service with Json directly. The controller has a utility designed to retrieve the body containing the Json from the HttpServlettRequest. There are other ways to do that I know.

My Test

package com.myproject.test;

import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import com.myproject.domain.Element;
import com.myproject.model.DbBrokerModel;
import com.myproject.rest.PostJsonRestTest;

// Not sure if you need any of this for your test so just delete it if you don't 
@Configuration
@PropertySource(value={
        "classpath:usermgmt.properties",
        "classpath:ldap.properties",
        "classpath:jdbc.properties",
        "classpath:email.properties"
})
@ContextConfiguration(locations = {
        "file:src/main/webapp/WEB-INF/spring-config.xml",
        "file:src/main/webapp/WEB-INF/conf/applicationContext-email.xml",
        "file:src/main/webapp/WEB-INF/conf/applicationContext-jdbc.xml"

})
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class PostJsonRestTest {


    private static final Logger log = Logger.getLogger(PostJsonRestTest.class);


    @Autowired
    private WebApplicationContext ctx;
    MockMvc mockMvc;

    @InjectMocks
    private PostJsonRest jsonRest;


    // TODO @Inject or @Autowired anything you may need 


    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.ctx).build();
    }

    @After
    public void tearDown() throws Exception {
    }


    /**
     * <b>triggerJsonPostTest</b><br/>
     * Explain what you are doing
     * 
     */
    @Test
    public void triggerJsonPostTest() {


        //Set up the model to be converted to Json
        TestModel requestModel = new TestModel();


        // Build the Model object and stuff them with test data
        List<Element> elements = new ArrayList<Element>();
        requestModel.setElementId("123");
        requestModel.setElementType("change");
        requestModel.setElementsAffected(3);
        requestModel.setChanges(elements);



        try {
            //Convert the Test Model To JSon
            ObjectMapper objectMapper = new ObjectMapper();
            byte[] requestJson =  objectMapper.writeValueAsBytes(requestModel);

            //Call your rest contoller 
            MvcResult result = this.mockMvc.perform(post("/test/receive-json")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(requestJson))
                    .andDo(print())
                    .andExpect(status().isOk())             
                    .andReturn();
            //TODO Wrtie a bunch of validation for the return OBJECT
            //TODO: Remember to test for positive and negative results in seperate @Test's 


        } catch (Exception e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

}

My Rest Controller So I am receiving Json in the HttpServlettRequest so you will see a utility method to retrieve the body from the request. You may or may not get any use out of it but its here for the purposes of my example.

package com.myproject.rest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * <b>PostJsonRest</b><br/>
 * Rest Controller Example
 * @author dhargis
 *
 *
 */
@Controller
public class PostJsonRest {

    private static final Logger log = Logger.getLogger(PostJsonRest.class);


    //TODO You may want to @Inject or @Autowire something here 

    /**
     * <b>receivePostJSon</b><br/>
     * Listens for properly formated JSon formated request of object type TestModel
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(
            value = "/trigger/receive-json", 
            method = RequestMethod.POST, 
            produces = {MediaType.APPLICATION_JSON_VALUE})
    @ResponseBody
    public void receivePostJSon(HttpServletRequest request, HttpServletResponse response) throws Exception{

        String body = "";
        try{
            //See below utility class 
            body =  getBody(request);

            //TODO You may want to log something here 

        }
        catch(IOException e){

            log.warn("Error: Problems parsing incoming JSON request  ", e);

        }

        finally{


        }

        // TODO REMOVE Temporary Output to the command line before deployment
        System.out.println(body);

    }

    /**
     * <b>getBody</b><br/>
     * This little utility class will give you the body containing the JSON
     * @param request
     * @return
     * @throws IOException
     */

    private String getBody(HttpServletRequest request) throws IOException {
        String body = null;
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
            log.error("Error while reading the request body", ex);
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    log.error("Error while closing the reading for request body", ex);
                    throw ex;
                }
            }
        }
        body = stringBuilder.toString();
        return body;
    }

}

Hope that helps good luck.

Upvotes: 0

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280132

Assuming

@ContextConfiguration(locations=("/spring/application-config.xml"))

refers to the XML configuration you've shown, there are no @Controller beans registered and therefore nothing to handle any requests.

Your @ContextConfiguration should probably be loading the dispatcher-servlet.xml file which is used by the DispatcherServlet. That context configuration file should contain

<mvc:annotation-driven /> 

to register any found @Controller beans as handlers.

Upvotes: 1

Related Questions