Hi,

I have 2 integration tests passing with Spring Boot (2.0.X, probably with version 1.X as well) but when I use the latest version 2.1.0, the first one is failing, it returns 404 instead of 200...

Any idea? I could not find any breaking change about this in the release note.

Thanks,

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MockMvcExampleTests {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testHomeUrl() throws Exception {
        this.mvc.perform(get("/home")).andExpect(status().isOk())
                .andExpect(content().string("Hello World"));
    }

    @Test
    public void testAdminHomeUrl() throws Exception {
        this.mvc.perform(get("/admin/home")).andExpect(status().isUnauthorized());
    }

    @Configuration
    public static class MyTestConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests().antMatchers("/admin/**").hasRole("USER").and()
                    .httpBasic();
        }
    }

    @Controller
    public static class TestController {

        @RequestMapping(path = "/home")
        public ResponseEntity<String> home() {
            return ResponseEntity.ok("Hello World");
        }

        @RequestMapping(path = "/admin/home")
        public ResponseEntity<String> adminHome() {
            return ResponseEntity.ok("Hello World Secured");
        }

    }

}

Comment From: wilkinsona

In Boot 2.1, your TestController isn't part of the application context but in Boot 2.0 it is. When the controller's missing, the test for /admin/home works due to your security configuration and it being rejected with a 401. The test for /home fails as the controller isn't found so there's nothing in the context to handle the request.

The change in behaviour is due to a change in Spring Framework. If you drop back to Boot 2.0.6 but override the Framework version to 5.1, you'll see the same failure. I believe this is due to the changes made in SPR-17206.

You can cause TestController to be picked up by annotating it with @TestConfiguration.

Comment From: fabianpiau

Yes, it is working now. Thanks a lot!

Comment From: singhpradeepkumar

I was facing same problem with Spring Boot 2.1 but @TestConfiguration does not seems to work in my case.

Please find the working code below.

@WebMvcTest(ReportController.class)
@ComponentScan(basePackages = "com.pkg")
public class ReportControllerTest {
    @Autowired
     private MockMvc mockMvc;
}

After adding @ComponentScan(basePackages = "com.pkg") issue has been resolved.

Comment From: rougou

@singhpradeepkumar I'm also facing a similar issue where @WebMvcTest(MyController.class) isn't enough to wire in MyController.class - which is what I think it's supposed to do - causing the 404. Adding @Import(MyController.class) makes everything work. I'll see if I can create a sample app reproducing this behavior.

Comment From: morenoian

In my case I had to combine some of the above steps to finally get my tests working:

On my controller to be tested:

@RestController
@RequestMapping(value = "/rest")
@TestConfiguration
public class SomeControllerImpl implements SomeController {

On my test class:

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeControllerImpl.class)
@Import(SomeControllerImpl.class)
public class SomeControllerImplTest {

Comment From: 4javier

I got to confirm that the problem is still there. Spring 5.13.17 Spring-Boot 2.6.5

This simple test executed with JUnit5 (Jupiter) fails with 404 if I strip the BrandController.class from @Import annotation's array. Adding that one, test passes. (No need for @TestConfiguration on BrandController class.)

@Import({SecurityConfig.class, BrandController.class})
@ActiveProfiles("RESTControllersTest")
@WebMvcTest(BrandController.class)

public class BrandControllerTest {

    @Configuration
    public static class TestContext{
        @Bean
        public static PropertySourcesPlaceholderConfigurer properties(){
            return new PropertySourcesPlaceholderConfigurer();
               }
    }


    @MockBean
    private BrandService brandService;
    @Autowired
    private MockMvc mockMvc;

    @Test
    void listBrands() throws Exception {

            mockMvc.perform(get("/brand/search"))
            .andExpect(status().isOk());
    }
}

The change in behaviour is due to a change in Spring Framework. If you drop back to Boot 2.0.6 but override the Framework version to 5.1, you'll see the same failure. I believe this is due to the changes made in SPR-17206.

I read that ticket you linked @wilkinsona , but in every docs I read about @WebMvcTest I see confirmation that

Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. @Controller, @ControllerAdvice, @JsonComponent, Converter/GenericConverter, Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not @Component, @Service or @Repository beans).

That should explicitly means that dropping of lite beans scanning (that's what I understood from that ticket, but far from be an expert about the matter) should not interfere with this annotation @Controllers auto configuration capability.

Comment From: wilkinsona

@4javier, the advice in this issue only applies to a controller that is nested within the test class. Looking at BrandControllerTest, you are not in that situation so the advice does not apply.

Your use of @Configuration on TestContext may be a problem but I cannot tell for certain as your example is incomplete. If you would like us to spend some more time investigating, please open a new issue providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to the issue.

Comment From: 4javier

@wilkinsona Thanks a lot. It looks like the root problem was indeed the @Configuration annotated inner class. Once I replaced it with @ImportAutoConfiguration(PropertyPlaceholderAutoConfiguration.class) on BrandControllerTest as per your suggestion on Gitter channel, I've been able to remove BrandController.class form @Import array.

Comment From: Robsonmendes1987

Estou com problema parecido, i,plementei o teste e retorna o texto "/ AssertionError: expected status to have been called with arguments 201 404 201 /" Meu codigo it('inserindo um produto', async function () { const res = {}; const req = { params: { productId: 1 }, body: {} }; // const id = req.params

res.status = sinon.stub().returns(res); res.json = sinon.stub().returns(); sinon.stub(productService, 'insertProducts') .resolves({ type: null, meesage: productFromDb })

await productControler.getAllProductById(req, res);

expect(res.status).to.have.calledWith(201);
expect(res.json).to.be.have.calledWith(productFromDb[0]);

})