wblanck
wblanck

Reputation: 51

Spring Controller Tests failing randomly

There is a project with 20 controllers approximately. Each controller has its corresponding test class. When we try to add new controller tests classes, some of the previous tests which were running fine, starts to fail randomly. If any controller test class is annotated with @Ignore, tests get back to normal.

This is the exception thrown by the failing tests:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: org.springframework.web.context.support.GenericWebApplicationContext@22f3fadf has been closed already.

Full log of one failing test:

 :: Spring Boot ::        (v2.0.3.RELEASE)
 
 2019-07-04T13:01:50,325 INFO  [pool-1-thread-17]
 o.s.b.StartupInfoLogger: Starting ZipCodeControllerTest on valhala
 with PID 17817 (started by wblanck in /home/wblanck/Projects/project)
 2019-07-04T13:01:50,325 DEBUG [pool-1-thread-17]
 o.s.b.StartupInfoLogger: Running with Spring Boot v2.0.3.RELEASE,
 Spring v5.0.7.RELEASE 2019-07-04T13:01:50,325 INFO  [pool-1-thread-17]
 o.s.b.SpringApplication: No active profile set, falling back to
 default profiles: default 2019-07-04T13:01:50,326 INFO 
 [pool-1-thread-17] o.s.c.s.AbstractApplicationContext: Refreshing
 org.springframework.web.context.support.GenericWebApplicationContext@a5a2b92:
 startup date [Thu Jul 04 13:01:50 ART 2019]; root of context hierarchy
 2019-07-04T13:01:50,448 INFO  [pool-1-thread-17]
 o.s.b.f.a.AutowiredAnnotationBeanPostProcessor: JSR-330
 'javax.inject.Inject' annotation found and supported for autowiring
 
 2019-07-04T13:01:50,772 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractHandlerMethodMapping$MappingRegistry: Mapped
 "{[/error]}" onto public
 org.springframework.http.ResponseEntity<java.lang.Object>
 com.package.controller.WrongPathErrorController.badPathError(javax.servlet.http.HttpServletRequest)
 2019-07-04T13:01:50,772 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractHandlerMethodMapping$MappingRegistry: Mapped
 "{[/api/users/{device}/zip-code],methods=[GET],produces=[application/json]}"
 onto public
 org.springframework.http.ResponseEntity<com.package.entity.CheckZipCodeProcedureResponseStatus>
 com.package.controller.ZipCodeController.checkZipCode(java.lang.Integer,java.lang.String,java.lang.String,java.lang.Integer,java.lang.String)
 
 ... more HandlerMethodMappings ...
 
 2019-07-04T13:01:50,773 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractHandlerMethodMapping$MappingRegistry: Mapped
 "{[/swagger-resources/configuration/ui]}" onto public
 org.springframework.http.ResponseEntity<springfox.documentation.swagger.web.UiConfiguration>
 springfox.documentation.swagger.web.ApiResourceController.uiConfiguration()
 2019-07-04T13:01:50,773 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractHandlerMethodMapping$MappingRegistry: Mapped
 "{[/swagger-resources]}" onto public
 org.springframework.http.ResponseEntity<java.util.List<springfox.documentation.swagger.web.SwaggerResource>>
 springfox.documentation.swagger.web.ApiResourceController.swaggerResources()
 2019-07-04T13:01:50,773 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractHandlerMethodMapping$MappingRegistry: Mapped
 "{[/swagger-resources/configuration/security]}" onto public
 org.springframework.http.ResponseEntity<springfox.documentation.swagger.web.SecurityConfiguration>
 springfox.documentation.swagger.web.ApiResourceController.securityConfiguration()
 2019-07-04T13:01:50,824 INFO  [pool-1-thread-17]
 s.d.s.w.PropertySourcedRequestMappingHandlerMapping: Mapped URL path
 [/v2/api-docs] onto method [public
 org.springframework.http.ResponseEntity<springfox.documentation.spring.web.json.Json>
 springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest)]
 2019-07-04T13:01:50,859 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractUrlHandlerMapping: Mapped URL path [/**/favicon.ico]
 onto handler of type [class
 org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
 2019-07-04T13:01:50,913 INFO  [pool-1-thread-17]
 o.s.w.s.m.m.a.RequestMappingHandlerAdapter: Looking for
 @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@a5a2b92:
 startup date [Thu Jul 04 13:01:50 ART 2019]; root of context hierarchy
 2019-07-04T13:01:50,931 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractUrlHandlerMapping: Mapped URL path [/webjars/**]
 onto handler of type [class
 org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
 2019-07-04T13:01:50,931 INFO  [pool-1-thread-17]
 o.s.w.s.h.AbstractUrlHandlerMapping: Mapped URL path [/**] onto
 handler of type [class
 org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
 2019-07-04T13:01:50,938 INFO  [pool-1-thread-17]
 o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: Detected
 @ExceptionHandler methods in integrationExceptionHandler
 2019-07-04T13:01:50,981 INFO  [pool-1-thread-17]
 o.s.m.w.MockServletContext: Initializing Spring FrameworkServlet ''
 2019-07-04T13:01:50,981 INFO  [pool-1-thread-17]
 o.s.w.s.FrameworkServlet: FrameworkServlet '': initialization started
 2019-07-04T13:01:50,987 INFO  [pool-1-thread-17]
 o.s.w.s.FrameworkServlet: FrameworkServlet '': initialization
 completed in 6 ms 2019-07-04T13:01:50,995 INFO  [pool-1-thread-17]
 o.s.c.s.DefaultLifecycleProcessor$LifecycleGroup: Starting beans in
 phase 2147483647 2019-07-04T13:01:50,995 INFO  [pool-1-thread-17]
 s.d.s.w.p.DocumentationPluginsBootstrapper: Context refreshed
 2019-07-04T13:01:50,995 INFO  [pool-1-thread-17]
 s.d.s.w.p.DocumentationPluginsBootstrapper: Found 1 custom
 documentation plugin(s) 2019-07-04T13:01:50,999 INFO 
 [pool-1-thread-17] s.d.s.w.s.ApiListingReferenceScanner: Scanning for
 api listing references 2019-07-04T13:01:51,109 INFO 
 [pool-1-thread-17] o.s.b.StartupInfoLogger: Started
 ZipCodeControllerTest in 0.813 seconds (JVM running for 39.78)
 2019-07-04T13:01:51,111 INFO  [pool-1-thread-17]
 o.s.c.s.AbstractApplicationContext: Closing
 org.springframework.web.context.support.GenericWebApplicationContext@40554129:
 startup date [Thu Jul 04 13:01:42 ART 2019]; root of context hierarchy
 2019-07-04T13:01:51,112 INFO  [pool-1-thread-17]
 o.s.c.s.DefaultLifecycleProcessor$LifecycleGroup: Stopping beans in
 phase 2147483647 Tests run: 3, Failures: 0, Errors: 1, Skipped: 0,
 Time elapsed: 14.141 s <<< FAILURE! - in
 com.package.controller.ZipCodeControllerTest
 testInexistentCheckZipCode(com.package.controller.ZipCodeControllerTest)
 Time elapsed: 10.648 s  <<< ERROR!
 org.springframework.web.util.NestedServletException: Request
 processing failed; nested exception is
 java.lang.IllegalStateException:
 org.springframework.web.context.support.GenericWebApplicationContext@22f3fadf
 has been closed already    at
 com.package.controller.ZipCodeControllerTest.testInexistentCheckZipCode(ZipCodeControllerTest.java:80)
 Caused by: java.lang.IllegalStateException:
 org.springframework.web.context.support.GenericWebApplicationContext@22f3fadf
 has been closed already    at
 com.package.controller.ZipCodeControllerTest.testInexistentCheckZipCode(ZipCodeControllerTest.java:80)

Tests are very similar, basically the common structure is:


@RunWith(SpringRunner.class)
@WebMvcTest(Controller.class)
public class ControllerTest {

    private static final String URL_TEMPLATE = ".....";

    @Autowired
    private MockMvc mvc;

    @Autowired
    private ObjectMapper mapper;

    @MockBean
    private Service service;

    private CustomParams params;
    private CustomRequest request;

    @Before
    public void init() {
        // initialize params and request ...
    }

    @Test
    public void methodOk() throws Exception {
        when(service.method(refEq(params))).thenReturn(RESPONSE);

        mvc.perform(MockMvcRequestBuilders.post(URL_TEMPLATE)
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(mapper.writeValueAsString(request)))
                .andExpect(status().isOk())
                .andExpect(jsonPath(STATUS_MESSAGE_PATH, is(MESSAGE_CODE_OK)))
                .andExpect(jsonPath(STATUS_CODE_PATH, is(STATUS_OK.getStatusCode()))));
    }


    @Test
    public void badRequest() throws Exception {
        mvc.perform(MockMvcRequestBuilders.post(URL_TEMPLATE))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath(ERROR_MESSAGE_PATH).isNotEmpty());
    }

Controllers have a structure like the following:

@RestController
public class Controller {

    private Service service;

    @PostMapping(value = "/api/some-url", produces = {"application/json"})
    public ResponseEntity<CustomResponse> method(
            @RequestHeader("someheaders") Integer someHeaders,
            @RequestBody CustomRequest someBody) {

        CustomParams params = new CustomParams();
        params.setApplicationType(applicationType);
        params.someHeaders(someHeaders);
        
        return service.method(params);
    }


I can't understand the reason of the exceptions and the fact that they occur in different tests in each run.

I've changed classes and variable's names due to confidentiality.

Upvotes: 5

Views: 5621

Answers (1)

Nir Levy
Nir Levy

Reputation: 12953

You should use DirtiesContext annotation on your tests. This will assure you'll get clean context on each test and they will not not interfere with eachother

Upvotes: 3

Related Questions