Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix test failing with "No ModelAndView found"?

This class is in the top of my tests hierarchy:

@TestPropertySource("/test.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public abstract class ApplicationAbstractTest {
}

And few more test classes:

@WebAppConfiguration
@ActiveProfiles("mysql")
abstract public class AbstractControllerTest extends ApplicationAbstractTest {

    protected MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @PostConstruct
    private void postConstruct() {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .apply(springSecurity())
                .build();
    }
}

JsonUserServiceTest:

@ActiveProfiles("json")
public class JsonUserServiceTest extends ApplicationAbstractTest {
    @Before
    public void setUp() throws Exception {
        ...
    }
}

ContactControllerTest:

public class ContactControllerTest extends AbstractControllerTest {
    @Test
    public void testGet() throws Exception {
        mockMvc.perform(get("/update-" + ID + "-contact")
                .with(userAuth(USER)))
//                .andExpect(status().isOk())
                .andDo(print())
                .andExpect(view().name("details"))
                .andExpect(forwardedUrl("/WEB-INF/jsp/details.jsp"));
    }
}

So, when I run ContactControllerTest along - it is successfull, and print method shows me:

Handler:
             Type = com.telecom.web.ContactController
           Method = public java.lang.String com.myApp.web.ContactController.details(java.lang.Integer,org.springframework.ui.ModelMap)

But when I run all tests, so JsonUserServiceTest runs first, ContactControllerTest fails. And print shows:

Handler:
             Type = null
...
java.lang.AssertionError: No ModelAndView found

What is wrong in configuration? Or how troubleshoot it?

UPD: at the same time, test like this, allways works fine:

public class UserControllerTest extends AbstractControllerTest {
    @Test
    public void testRegister() throws Exception {
        mockMvc.perform(get("/register"))
                .andDo(print())
                .andExpect(view().name("profile"))
                .andExpect(forwardedUrl("/WEB-INF/jsp/profile.jsp"));
    }
}

UPD: There is controller's method I'm testing:

@GetMapping("/update-{id}-contact")
public String details(@PathVariable Integer id, ModelMap model) {
    Integer userId = AuthorizedUser.id();
    LOG.info("get contact {} for User {}", id, userId);
    Contact contact = service.get(id, userId);
    model.addAttribute("contact", contact);
    return "details";
}

I also have such bean:

@Bean
public InternalResourceViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/jsp/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

UPD: I've tried configure mockMvc in separate class:

@Configuration
public class TestConfig {

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Bean
    public MockMvc mockMvc() {
        return MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .apply(springSecurity())
                .build();
    }
}

And added it here:

@WebAppConfiguration
@ContextConfiguration(classes = {TestConfig.class})
@ActiveProfiles("mysql")
abstract public class AbstractControllerTest extends ApplicationAbstractTest {

but I've received:

java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.

like image 401
Pavlo Plynko Avatar asked Mar 26 '17 20:03

Pavlo Plynko


2 Answers

The WARN message doesn't cause the test cases to fail. It just says that Entity manager factory is registered twice. This will only be an issue if you cluster your application using the same Entity Manager Factory. For test case run it is not a cause for concern.

The root cause of the testcase failure is in these two lines

 .andExpect(view().name("details"))
 .andExpect(forwardedUrl("/WEB-INF/jsp/details.jsp"));

Please check if the project has a view named "details" and the forwardded url is "/WEB-INF/jsp/details.jsp"

Update

Could you please try this

@Configuration
public class TestConfig {


@Autowired
private Filter springSecurityFilterChain;

@Autowired
private WebApplicationContext webApplicationContext;

@Bean
public MockMvc mockMvc() {
    return MockMvcBuilders
            .webAppContextSetup(webApplicationContext)
            .apply(springSecurityFilterChain)
            .build();
}
}
like image 169
Abdul Rahman Avatar answered Sep 16 '22 11:09

Abdul Rahman


Create a configuration file that will initialize mocking objects for your test cases. And put at all test case classes.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfig.class})

It will initialize all your mocking objects only once and cached after that and reused for all test cases.

Or if you don't want to use mocking configuration, you can directly pass the actual application configuration to ContextConfiguration as below

For annotation based application configuration (here AppConfig and AppConfig2 are your configuration class)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class, AppConfig2.class})

For xml based application configuration (here appConfig.xml and appConfig2.xml are your configuration files)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:pathTo/appConfig.xml","classpath:pathTo/appConfig2.xml"})

Reference : JUnit + Spring integration example

like image 42
Anil Agrawal Avatar answered Sep 19 '22 11:09

Anil Agrawal