Spring boot test not recognizing servlet

2.4k views Asked by At

I have got Spring Boot Application and I want to test it. I do not use Spring Controllers, but I use Servlet with service method. Also I have got my configuration class that provides ServletRegistrationBean. But every time when I try to perform mock request I get 404 error. There is no call to servlet at all. I think that Spring does not find this servlet. How could I fix it? While I am launching app at localhost everything works fine.

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class SpringDataProcessorTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void retrieveByRequest() throws Exception{
        mockMvc.perform(buildRetrieveCustomerByIdRequest("1")).andExpect(status().isOk());

    }

    private MockHttpServletRequestBuilder buildRetrieveCustomerByIdRequest(String id) throws Exception {
        return get(String.format("/path/get('%s')", id)).contentType(APPLICATION_JSON_UTF8);
    }
}

Configuration:

@Configuration
public class ODataConfiguration extends WebMvcConfigurerAdapter {
    public String urlPath = "/path/*";


    @Bean
    public ServletRegistrationBean odataServlet(MyServlet servlet) {
        return new ServletRegistrationBean(servlet, new String[] {odataUrlPath});
    }
}

MyServlet:

@Component
public class MyServlet extends HttpServlet {

    @Autowired
    private ODataHttpHandler handler;


    @Override
    @Transactional
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            handler.process(req, resp);
        } catch (Exception e) {
            log.error("Server Error occurred", e);
            throw new ServletException(e);
        }
    }
}
1

There are 1 answers

5
M. Deinum On BEST ANSWER

If you really want to use MockMvc to test your code instead of a Servlet use a HttpRequestHandler and use a SimpleUrlHandlerMapping to map it to a URL.

Something like the following.

@Bean
public HttpRequestHandler odataRequestHandler(ODataHttpHandler handler) {
    return new HttpRequestHandler() {
        public void handleRequest() {
            try {
                handler.process(req, resp);
            } catch (Exception e) {
                log.error("Server Error occurred", e);
                throw new ServletException(e);
            }
        }
    }
}

And for the mapping

@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
    mapping.setUrlMap(Collections.singletonMap(odataUrlPath, "odataRequestHandler"); 
    return mapping;
}

Another solution would be to wrap it in a controller instead of a servlet.

@Controller
public class ODataController {

    private final ODataHttpHandler handler;

    public ODataController(ODataHttpHandler handler) {
        this.handler=handler;
    }

    @RequestMapping("/path/*")
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException {
        try {
            handler.process(req, resp);
        } catch (Exception e) {
            log.error("Server Error occurred", e);
            throw new ServletException(e);
        }
    }
}

In either way your handler should be served/processed by the DispatcherServlet and thus can be tested using MockMvc.