如何修复 "No ModelAndView found" 导致的测试失败?
How to fix test failing with "No ModelAndView found"?
这个 class 在我的测试层次结构的顶部:
@TestPropertySource("/test.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public abstract class ApplicationAbstractTest {
}
还有一些测试 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"));
}
}
所以,当我 运行 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 class:
@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 cannot be
null. Ensure a Bean with the name springSecurityFilterChain
implementing Filter is present or inject the Filter to be used.
WARN 消息不会导致测试用例失败。它只是说实体管理器工厂被注册了两次。如果您使用相同的 Entity Manager Factory 集群您的应用程序,这只会是一个问题。对于测试用例运行,这不是一个值得关注的问题。
测试用例失败的根本原因在这两行
.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();
}
}
创建一个配置文件,为您的测试用例初始化模拟对象。并放入所有测试用例 classes.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfig.class})
它只会初始化所有模拟对象一次并在之后缓存并重复用于所有测试用例。
Or if you don't want to use mocking configuration, you can directly
pass the actual application configuration to ContextConfiguration as
below
用于基于注释的应用程序配置(此处 AppConfig 和 AppConfig2 是您的配置 class)
@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"})
这个 class 在我的测试层次结构的顶部:
@TestPropertySource("/test.properties")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public abstract class ApplicationAbstractTest {
}
还有一些测试 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"));
}
}
所以,当我 运行 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 class:
@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 cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
WARN 消息不会导致测试用例失败。它只是说实体管理器工厂被注册了两次。如果您使用相同的 Entity Manager Factory 集群您的应用程序,这只会是一个问题。对于测试用例运行,这不是一个值得关注的问题。
测试用例失败的根本原因在这两行
.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();
}
}
创建一个配置文件,为您的测试用例初始化模拟对象。并放入所有测试用例 classes.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfig.class})
它只会初始化所有模拟对象一次并在之后缓存并重复用于所有测试用例。
Or if you don't want to use mocking configuration, you can directly pass the actual application configuration to ContextConfiguration as below
用于基于注释的应用程序配置(此处 AppConfig 和 AppConfig2 是您的配置 class)
@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"})