我正在开发一个Spring MVC 3.2 Web应用程序,我正在尝试在我的单元测试中使用新的MockMvc测试实用程序.我想测试各个控制器以及整个Web应用程序加载我的Spring配置XML文件.从Javadoc看,我想对前者使用standaloneSetup,对后者使用webAppContextSetup.
但是,当我的控制器寻找消息转换器来转换输出时,我遇到了问题.我对standaloneSetup方法的Javadoc的解释似乎不正确.这是这个方法的Javadoc:
通过注册一个或多个@Controller的实例并以编程方式配置Spring MVC基础结构来构建MockMvc.这允许完全控制控制器的实例化和初始化及其依赖性,类似于普通单元测试,同时还可以一次测试一个控制器.
使用此选项时,将自动创建DispatcherServlet为带有带注释的控制器的请求提供服务所需的最小基础结构,并且可以对其进行自定义,从而导致配置与MVC Java配置提供的配置相同,但使用构建器样式方法除外.
如果应用程序的Spring MVC配置相对简单,例如在使用MVC命名空间或MVC Java配置时,那么使用此构建器可能是测试大多数控制器的好选择.可以使用少得多的测试来专注于测试和验证实际的Spring MVC配置.
我已经解释了"最小基础设施"和"及其依赖关系",意味着我指定的控制器除了所有依赖项外都会加载,我将其包含在消息转换器中.但是,情况似乎并非如此.我需要一个针对2个要求的自定义配置:
消耗"application/json"的PUT操作,该操作被转换为带有Joda DateTime字段的POJO.因此,我在Spring配置中包含以下内容:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="myObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Run Code Online (Sandbox Code Playgroud)
这适用于webAppContextSetup但是如果我想使用standaloneSetup,我看起来需要手动创建和配置使用我自定义的ObjectMapper配置的MappingJackson2HttpMessageConverter,它注册了JodaModule.
standaloneSetup(myController).setMessageConverters(myJsonConverter).build();
Run Code Online (Sandbox Code Playgroud)生成"application/custom + xml"的GET操作.当我加载webAppContextSetup时,无需额外配置即可运行.但是,当我加载standaloneSetup时,之前发生的任何Spring配置都没有发生,我看到以下错误消息:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
Run Code Online (Sandbox Code Playgroud)
有人可以描述这里发生了什么吗?我调用webAppContextSetup时是否包含一些隐藏或默认的消息转换器但是当我调用上面的代码时,我会以某种方式覆盖这些转换器?我怎么能包括它们?
MockMvc是否有更简单的方法来设置单个控制器以及mvc:annotation-driven中的所有配置?我可以配置MockMvcBuilders.standaloneSetup()以使用我的消息转换器XML配置而不是手动配置每个配置吗?
我试图遵循本文[1]在Spring MvcMock测试中模拟安全性。
我要测试的REST服务如下所示:
@RequestMapping(value = "/something/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deleteXXX(@ActiveUser AppUser user, @PathVariable(value = "id") Long id) {
...
}
Run Code Online (Sandbox Code Playgroud)
其中@ActiveUser是的自定义实现/扩展@AuthenticationPrincipal和,AppUser是自定义UserDetails实现。
在测试中,我这样做:
mockMvc.perform(delete("/something/{i}", "123").with(user(new AppUser(...))));
Run Code Online (Sandbox Code Playgroud)
我还添加了一些TestExecutionLIsteners:
@TestExecutionListeners(listeners = { ServletTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class, WithSecurityContextTestExecutionListener.class })
Run Code Online (Sandbox Code Playgroud)
```
但是它失败了:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.corp.AppUser]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.corp.AppUser.<init>()
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:885)
Run Code Online (Sandbox Code Playgroud)
可以,因为AppUser它没有默认的构造函数,但是框架实际上不应该创建用户,而是使用我传递给测试的那个。
为了在运行时解决此问题,我必须将 …
我在我的 java 配置中定义了消息源:
@Bean(name = "messageSource")
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames(
"/i18n/ir/kia/industry/webapp/entity",
"/i18n/ir/kia/industry/webapp/formErrors",
"/i18n/ir/kia/industry/webapp/frontend",
"/i18n/ir/kia/industry/webapp/frontendPages");
return messageSource;
}
Run Code Online (Sandbox Code Playgroud)
当使用站点和消息正确显示时它工作正常,但是当尝试使用以下内容编写 spring 测试时:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestContext.class, SpringMVC.class})
@WebAppConfiguration
public abstract class AbstractTestClass {
protected MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
Run Code Online (Sandbox Code Playgroud)
和一个简单地扩展它的测试类,我得到错误Can't find bundle for base name /i18n/ir/kia/industry/webapp/entity。
它在启动 tomcat 并在 jsp 文件中使用消息源时工作正常,但在测试时没有运气。我曾尝试在 WEB-INF 下移动 i18n 文件夹,但它也没有帮助。
目标文件夹看起来像这样,请不要告诉我将 i18n 文件夹添加到目标资源...

我们正在使用 spring boot (v1.3.3.RELEASE) 构建一个项目,我们有一个自定义的 ErrorController ,如下所示
@RestController
@RequestMapping("/error")
public class GlobalErrorController extends AbstractErrorController {
@Autowired
public GlobalErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes);
}
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping(produces = MediaType.ALL_VALUE)
public ResponseEntity error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status.is5xxServerError()) {
//log maybe
}
return new ResponseEntity(status);
}
}
Run Code Online (Sandbox Code Playgroud)
当我们启动Spring Boot应用程序并尝试通过curl或浏览器访问它时,我们发现它运行良好,它只响应状态代码而没有正文(内容)。
但是当我们尝试为这个控制器编写集成测试时,我们发现ErrorController永远不会被调用,一些示例代码如下:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {MyApplication.class, TestConfiguration.class})
@WebAppConfiguration
public class GlobalErrorControllerIntegrationTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Before
public void setUp() throws Exception { …Run Code Online (Sandbox Code Playgroud) 我正在与:
\n\n我有以下来自服务器的响应:
\n\nMockHttpServletResponse:\n Status = 200\n Error message = null\n Headers = {Content-Type=[application/json;charset=UTF-8]}\n Content type = application/json;charset=UTF-8\n Body = {\n "id" : "100",\n "nombre" : "Jes\xc3\xbas Voc\xc3\xaa",\n "apellido" : "M\xc3\xa3o Nu\xc3\xb1ez",\n "fecha" : "1977-12-08"\n}\n Forwarded URL = null\n Redirected URL = null\nRun Code Online (Sandbox Code Playgroud)\n\n以下内容按预期工作(有效):
\n\n .andExpect(jsonPath("$").exists())\n .andExpect(jsonPath("$", notNullValue()))\n .andExpect(jsonPath("$", isA(LinkedHashMap.class)))\n\n .andExpect(jsonPath("$.*").exists())\n .andExpect(jsonPath("$.*", notNullValue()))\n .andExpect(jsonPath("$.*", isA(JSONArray.class)))\n .andExpect(jsonPath("$.*", hasSize(is(4))))\nRun Code Online (Sandbox Code Playgroud)\n\n我需要的测试("$")是 1。确认存在 1 项。兹再次确认以下事项:
Body = {\n …Run Code Online (Sandbox Code Playgroud) 我正在研究这个JPA QueryDSL例子.在这个例子中我创建了PersonDaoTest.java.早些时候我使用较低版本的spring-test客户端要求更新它的最新版本,所以我使用4.3.1.RELEASE.当我使用这个版本时,我看到它import org.springframework.test.context.transaction.TransactionConfiguration;是@deprecated.有谁能告诉我import org.springframework.test.context.transaction.TransactionConfiguration;最新版本的更换?
PersonDaoTest.java
@ContextConfiguration("/test-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class PersonDaoTest {
@Autowired
private PersonDao personDao;
//
@Test
public void testCreation() {
personDao.save(new Person("Erich", "Gamma"));
final Person person = new Person("Kent", "Beck");
personDao.save(person);
personDao.save(new Person("Ralph", "Johnson"));
final Person personFromDb = personDao.findPersonsByFirstnameQueryDSL("Kent").get(0);
Assert.assertEquals(person.getId(), personFromDb.getId());
}
@Test
public void testMultipleFilter() {
personDao.save(new Person("Erich", "Gamma"));
final Person person = personDao.save(new Person("Ralph", "Beck"));
final Person person2 = personDao.save(new Person("Ralph", …Run Code Online (Sandbox Code Playgroud) 我在尝试运行测试时遇到以下错误:
org.springframework.web.util.NestedServletException:请求处理失败; 嵌套异常是java.lang.IllegalStateException:Validator [userCreateFormValidator bean]的目标无效:com.ar.empresa.forms.UserCreateForm@15c3585
引起:java.lang.IllegalStateException:验证器[userCreateFormValidator bean]的目标无效:com.ar.empresa.forms.UserCreateForm@15c3585 org.springframework.valid.VeridFatate.alsert位于sun.reflect.NativeMethodAccessorImpl的sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)的com.ar.empresa.controllers.UserController.initBinder(UserController.java:36)中的.validation.DataBinder.addValidators(DataBinder.java:578) .invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)
代码是:
控制器:
@Controller
public class UserController {
private UserService userService;
private UserCreateFormValidator userCreateFormValidator;
@Autowired
public UserController(UserService userService, UserCreateFormValidator userCreateFormValidator) {
this.userService = userService;
this.userCreateFormValidator = userCreateFormValidator;
}
@InitBinder("form")
public void initBinder(WebDataBinder binder) {
binder.addValidators(userCreateFormValidator);
}
@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/user/create", method = RequestMethod.GET)
public ModelAndView getUserCreatePage() {
return new ModelAndView("user_create", "form", new UserCreateForm());
}
@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/user/create", method = RequestMethod.POST)
public String handleUserCreateForm(@Valid @ModelAttribute("form") UserCreateForm form, BindingResult bindingResult) …Run Code Online (Sandbox Code Playgroud) 根据Spring Boot Docs,@TestConfiguration测试应自动检测嵌套。
但是在我的测试代码中,当我运行整个测试类时它是有问题的,即使我通过@Import. 测试代码结构如下:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
//@Import(IntegrationTests.TestSecurityConfig.class)
public class IntegrationTests {
// test methods
// test configuration
@TestConfiguration
static class TestSecurityConfig {}
}
Run Code Online (Sandbox Code Playgroud)
当我单独运行单个测试用例(测试方法)时,所有测试都按预期通过,但是当我直接运行测试类时,有些测试失败了,@TestConfiguration没有应用于测试。
这样做的完整代码IntegrationTests是在这里。
更新:在我的代码中添加了一种解决方法以使测试通过。
@TestComponent
@Slf4j
static class TestUserDetailsService implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
TestUserDetailsService(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = User.withUsername("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.disabled(false) …Run Code Online (Sandbox Code Playgroud) spring spring-test spring-test-mvc spring-boot spring-boot-test
控制器
@RestController
@Validated
class MyController {
@GetMapping("/foo")
public String unwrapped(@Min(1) @RequestParam("param") int param) {
return Integer.toString(param);
}
@GetMapping("/bar")
public String wrapped(@ModelAttribute @Valid Wrapper bean) {
return Integer.toString(bean.param);
}
static class Wrapper {
@Min(1)
int param;
public void setParam(final int param) {
this.param = param;
}
}
}
Run Code Online (Sandbox Code Playgroud)
测试
public class MyControllerTest {
MyController controller = new MyController();
MockMvc mockMvc = MockMvcBuilders
.standaloneSetup(this.controller)
.build();
@Test // fails
public void unwrapped() throws Exception {
this.mockMvc.perform(get("/foo")
.param("param", "0"))
.andExpect(status().isBadRequest());
}
@Test // passes …Run Code Online (Sandbox Code Playgroud) 我正在构建一个自定义入门库,它在 WebMvcConfigurer 类中注册一个 ObjectMapper。此 ObjectMapper 上的设置之一是即时序列化格式。
当我将 @SpringBootTest 与 @AutoConfigureMockMvc 一起使用时,将拾取配置的 ObjectMapper,并且一切按预期工作。然而,使用 @WebMvcTest 的相同断言失败了。似乎 WebMvcConfigurer 类没有在 @WebMvcTest 自动配置中被拾取,尽管文档声明应该拾取它。
有没有办法扩展 WebMvcTest 的自动配置,而不必将 @Import 与每个 @WebMvcTest 注释一起放置?
spring-test-mvc ×10
spring-test ×7
spring ×6
spring-mvc ×5
spring-boot ×4
java ×2
mockmvc ×2
hamcrest ×1
json ×1
querydsl ×1
testng ×1
unit-testing ×1