【问题标题】:How to fix test failing with "No ModelAndView found"?如何修复测试失败并出现“未找到 ModelAndView”?
【发布时间】:2017-08-19 10:08:08
【问题描述】:

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

@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
public InternalResourceViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/jsp/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

UPD:我尝试在单独的类中配置 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 实现过滤器存在或注入要使用的过滤器。

【问题讨论】:

  • 如果你从 JsonUserServiceTest 中删除 @ActiveProfiles("json") 并运行套装会发生什么。 ContactControllerTest 是否有效?
  • 是的,ContactControllerTest 在这种情况下有效(但正如预期的那样,JsonUserServiceTest 无效)。
  • @ActiveProfiles 接受一个数组。如果你给它@ActiveProfiles({ "json", "mysql" })会发生什么?
  • 它给出了NoUniqueBeanDefinitionException,因为我有两个存储库实现,用不同的配置文件标记:@Profile("json")@Profile("mysql")

标签: java unit-testing spring-mvc spring-boot applicationcontext


【解决方案1】:

WARN 消息不会导致测试用例失败。它只是说实体管理器工厂注册了两次。仅当您使用相同的实体管理器工厂对应用程序进行集群时,这才会成为问题。对于测试用例运行,无需担心。

testcase失败的根本原因就在这两行

 .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”配置文件进行其他测试)时它是如何通过的?我已经用我正在测试的方法更新了问题。
【解决方案2】:

创建一个配置文件,为您的测试用例初始化模拟对象。并放在所有测试用例类中。

@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 integration example

【讨论】:

  • 也许你能告诉我如何正确地做到这一点?我用我的尝试示例更新了问题。
  • 最后我配置了TestConfig.class并把@ContextConfiguration(classes = {TestConfig.class}),得到了同样的错误:No ModelAndView found
  • 您能否详细说明您的应用程序是如何初始化的?意味着您使用的是基于 xml 的配置还是基于注释的配置。假设您正在使用基于注释的配置,并且您在 WebConfig.java 中初始化了您的 webApp,那么您可以直接将 WebConfig.class 作为参数传递给 ContextConfiguration。如果您使用基于 xml 的配置,您可以直接将 xml 名称作为参数传递给 ContextConfiguration
猜你喜欢
  • 1970-01-01
  • 2015-05-28
  • 2015-01-16
  • 2014-12-02
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多