使用 MockServletContext 进行单元测试
Unit testing with MockServletContext
我已经使用 Gradle 设置了 spring boot 应用程序。现在我明白 @EnableAutoConnfiguration 根据 class 路径中的依赖项配置应用程序。我很高兴避免所有的管道,但事情开始发生,我希望不会发生。
这是我的依赖项:
dependencies {
compile('org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE')
compile 'org.springframework.hateoas:spring-hateoas:0.17.0.RELEASE'
compile 'org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'com.google.guava:guava:18.0'
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
compile 'commons-beanutils:commons-beanutils:1.9.2'
runtime 'org.hsqldb:hsqldb:2.3.2'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'com.jayway.jsonpath:json-path:2.0.0'
}
我的申请class:
@ComponentScan("org.home.project")
@SpringBootApplication
//@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
来自 UserController 的片段:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity<ResourceSupport> create(@Valid @RequestBody UserCreateRequest ucr, BindingResult bindingResult) {
if (bindingResult.hasErrors()) throw new InvalidRequestException("Bad Request", bindingResult);
Long userId = userService.create(ucr);
ResourceSupport resource = new ResourceSupport();
resource.add(linkTo(UserEndpoint.class).withSelfRel());
resource.add(linkTo(methodOn(UserEndpoint.class).update(userId, null, null)).withRel(VIEW_USER));
resource.add(linkTo(methodOn(UserEndpoint.class).delete(userId)).withRel(DELETE_USER));
return new ResponseEntity(resource, HttpStatus.CREATED);
}
UserController.java有两个注解:
@RestController
@RequestMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
首先 - 注意注释掉的@EnableHyperdiaSupport 注释 - ResourceSupport 实例中的链接仍然序列化为 hal+json 格式,尽管生成了媒体类型并且在请求中设置了媒体类型。当在依赖项中引入 'org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE' 时,这会自动发生。如何明确配置它?
另一个问题是单元测试。
这通过了:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class UserControllerTest {
...ommited for brevity...
@InjectMocks
private UserController testObject;
@Before
public void setUp() throws Exception {
initMocks(this);
mockMvc = standaloneSetup(testObject).build();
}
@Test
public void testUserCreatedLinks() throws Exception {
mockMvc.perform(post("/users").contentType(MediaType.APPLICATION_JSON).content(data))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andExpect(jsonPath("$.links.[*].rel", hasItem("self")));
}
...ommited fro brevity...
}
post 请求 returns 测试中的标准 JSON 响应 - 而不是 HAL+JSON。有没有办法重新配置它,以便使用 MockServletContext 对 @RestController 进行单元测试会产生 HAL+JSON 或回到问题编号 1 - 如何显式配置响应格式,以便 Jackson 序列化器不会产生 hal+json ?
您正在使用 Spring MVC 测试的 standaloneSetup
运行ning 测试,它使用最低限度的配置来启动您的控制器并 运行ning。该配置与 运行 整个应用程序时将使用的配置不同。
如果你想使用相同的配置,你可以使用webAppContextSetup
:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SomeTests {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
}
或者,您可以在独立设置中复制 Spring HATEOAS 的配置。请注意,这 运行 存在测试配置偏离应用程序配置的风险。您将像这样创建 MockMvc
实例:
TypeConstrainedMappingJackson2HttpMessageConverter messageConverter =
new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class);
messageConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));
ObjectMapper objectMapper = messageConverter.getObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.setHandlerInstantiator(
new Jackson2HalModule.HalHandlerInstantiator(new DefaultRelProvider(), null));
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(testObject)
.setMessageConverters(messageConverter).build();
我已经使用 Gradle 设置了 spring boot 应用程序。现在我明白 @EnableAutoConnfiguration 根据 class 路径中的依赖项配置应用程序。我很高兴避免所有的管道,但事情开始发生,我希望不会发生。
这是我的依赖项:
dependencies {
compile('org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE')
compile 'org.springframework.hateoas:spring-hateoas:0.17.0.RELEASE'
compile 'org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'com.google.guava:guava:18.0'
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
compile 'commons-beanutils:commons-beanutils:1.9.2'
runtime 'org.hsqldb:hsqldb:2.3.2'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'com.jayway.jsonpath:json-path:2.0.0'
}
我的申请class:
@ComponentScan("org.home.project")
@SpringBootApplication
//@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
来自 UserController 的片段:
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity<ResourceSupport> create(@Valid @RequestBody UserCreateRequest ucr, BindingResult bindingResult) {
if (bindingResult.hasErrors()) throw new InvalidRequestException("Bad Request", bindingResult);
Long userId = userService.create(ucr);
ResourceSupport resource = new ResourceSupport();
resource.add(linkTo(UserEndpoint.class).withSelfRel());
resource.add(linkTo(methodOn(UserEndpoint.class).update(userId, null, null)).withRel(VIEW_USER));
resource.add(linkTo(methodOn(UserEndpoint.class).delete(userId)).withRel(DELETE_USER));
return new ResponseEntity(resource, HttpStatus.CREATED);
}
UserController.java有两个注解:
@RestController
@RequestMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
首先 - 注意注释掉的@EnableHyperdiaSupport 注释 - ResourceSupport 实例中的链接仍然序列化为 hal+json 格式,尽管生成了媒体类型并且在请求中设置了媒体类型。当在依赖项中引入 'org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE' 时,这会自动发生。如何明确配置它?
另一个问题是单元测试。
这通过了:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class UserControllerTest {
...ommited for brevity...
@InjectMocks
private UserController testObject;
@Before
public void setUp() throws Exception {
initMocks(this);
mockMvc = standaloneSetup(testObject).build();
}
@Test
public void testUserCreatedLinks() throws Exception {
mockMvc.perform(post("/users").contentType(MediaType.APPLICATION_JSON).content(data))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andExpect(jsonPath("$.links.[*].rel", hasItem("self")));
}
...ommited fro brevity...
}
post 请求 returns 测试中的标准 JSON 响应 - 而不是 HAL+JSON。有没有办法重新配置它,以便使用 MockServletContext 对 @RestController 进行单元测试会产生 HAL+JSON 或回到问题编号 1 - 如何显式配置响应格式,以便 Jackson 序列化器不会产生 hal+json ?
您正在使用 Spring MVC 测试的 standaloneSetup
运行ning 测试,它使用最低限度的配置来启动您的控制器并 运行ning。该配置与 运行 整个应用程序时将使用的配置不同。
如果你想使用相同的配置,你可以使用webAppContextSetup
:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SomeTests {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
}
或者,您可以在独立设置中复制 Spring HATEOAS 的配置。请注意,这 运行 存在测试配置偏离应用程序配置的风险。您将像这样创建 MockMvc
实例:
TypeConstrainedMappingJackson2HttpMessageConverter messageConverter =
new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class);
messageConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));
ObjectMapper objectMapper = messageConverter.getObjectMapper();
objectMapper.registerModule(new Jackson2HalModule());
objectMapper.setHandlerInstantiator(
new Jackson2HalModule.HalHandlerInstantiator(new DefaultRelProvider(), null));
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(testObject)
.setMessageConverters(messageConverter).build();