如何修复测试失败并出现"No ModelAndView found"错误?

6

这个类是我测试层次结构的顶层:

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

还有几个测试类:

@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"));
    }
}

因此,当我运行ContactControllerTest时,它是成功的,并且print方法向我显示:
Handler:
             Type = com.telecom.web.ContactController
           Method = public java.lang.String com.myApp.web.ContactController.details(java.lang.Integer,org.springframework.ui.ModelMap)

但是当我运行所有测试时,JsonUserServiceTest 先运行,ContactControllerTest 失败了。并且 print 显示:
Handler:
             Type = null
...
java.lang.AssertionError: No ModelAndView found

配置出了什么问题?或者如何进行故障排除?

更新: 同时,像这样的测试总是正常工作:

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"));
    }
}

更新: 我正在测试的是控制器方法:

@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";
}

我也有这样的bean:
@Bean
public InternalResourceViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/jsp/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

更新:我已经尝试在单独的类中配置mockMvc:

@Configuration
public class TestConfig {

    @Autowired
    private WebApplicationContext webApplicationContext;

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

并将其添加到此处:

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

但是我收到了以下信息:

java.lang.IllegalStateException: springSecurityFilterChain 不能为空。请确保存在名称为springSecurityFilterChain的Bean,且实现了Filter接口或注入要使用的Filter。


1
如果从JsonUserServiceTest中删除@ActiveProfiles("json")并运行测试套件,会发生什么?ContactControllerTest是否能正常工作? - johncena
是的,在这种情况下ContactControllerTest可以工作(但是,JsonUserServiceTest不起作用是预期的)。 - Pavlo Plynko
@ActiveProfiles 接受一个数组。如果你给它 @ActiveProfiles({ "json", "mysql" }),会发生什么? - Roddy of the Frozen Peas
它会抛出NoUniqueBeanDefinitionException异常,因为我有两个存储库实现,分别标记有不同的配置文件:@Profile("json")@Profile("mysql") - Pavlo Plynko
2个回答

5

警告信息不会导致测试用例失败。它只是说明实体管理工厂被注册了两次。只有在使用相同的实体管理工厂对应用程序进行集群处理时,这才会成为一个问题。对于测试用例运行而言,这不是一个令人担忧的原因。

测试用例失败的根本原因在于以下两行代码。

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

请检查项目中是否有名为“details”的视图,并且转发的URL为“/WEB-INF/jsp/details.jsp”。 更新 请尝试这个。
@Configuration
public class TestConfig {


@Autowired
private Filter springSecurityFilterChain;

@Autowired
private WebApplicationContext webApplicationContext;

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

但是当我独立运行它(或使用“mysql”配置文件运行其他测试)时,它是如何通过的?我已经更新了问题,并附上了我正在测试的方法。 - Pavlo Plynko
给我一个提示:你从哪里进口滤芯? - sedub01

3
创建一个配置文件,用于初始化测试用例的模拟对象,并将其放置在所有测试用例类中。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfig.class})

它将仅初始化所有模拟对象一次,并在此之后缓存并重用于所有测试用例。

或者,如果您不想使用模拟配置,可以直接将实际的应用程序配置传递给ContextConfiguration,如下所示

对于基于注释的应用程序配置(这里的AppConfig和AppConfig2是您的配置类)

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

针对基于XML的应用程序配置(这里的appConfig.xml和appConfig2.xml是您的配置文件)

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

参考:JUnit + Spring 集成示例


这是一个关于 JUnit 和 Spring 集成的示例。

也许你可以告诉我如何正确地做吗?我已经在问题中更新了我的尝试示例。 - Pavlo Plynko
最后我配置了 TestConfig.class 并添加了 @ContextConfiguration(classes = {TestConfig.class}),但是仍然出现了相同的错误:未找到ModelAndView - Pavlo Plynko
请问您能详细说明一下您的应用程序是如何初始化的吗?也就是说,您是使用基于XML的配置还是基于注释的配置。假设您正在使用基于注释的配置,并且您在WebConfig.java中初始化了您的WebApp,那么您可以直接将WebConfig.class作为参数传递给ContextConfiguration。如果您正在使用基于XML的配置,则可以直接将XML名称作为参数传递给ContextConfiguration。 - Anil Agrawal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接