我已经尝试了一段时间,使用MockMvc
,Mockito
和Cucumber
来测试我的REST控制器端点。
我的目标是测试我的服务层,而无需调用实际的实现。 (因此,我不希望数据出现在数据库中)
在处理大型项目时,我想避免使用“内存中”数据库。
我最近可以使用它,没有进行模拟,但是由于我尝试模拟测试,因此我收到了NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
AddressController
代码段@Autowired
private AddressManager addressManager;
@GetMapping(value = "/{id}")
public ResponseEntity<Object> getAddress(@PathVariable("id") Long addressId) {
return new ResponseEntity<>(addressManager.getAddress(addressId), HttpStatus.OK);
// getAddress calls a data manager layer which then calls addressRepo.findOneById(addressId);
}
@PostMapping(value = "/add")
public ResponseEntity<Object> addAddress(@RequestBody Address address) {
return new ResponseEntity<>(addressManager.addAddress(address), HttpStatus.OK);
// addAddress calls a data manager layer which then calls addressRepo.save(address);
}
AddressStepDefs
代码段@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(webEnvironment= WebEnvironment.MOCK)
@Transactional
@AutoConfigureMockMvc
public class AddressStepDefs {
private MockMvc mockMvc;
private ResultActions result; // allows to track result
@InjectMocks
private AddressController addressController;
@Mock
private AddressDataManager addressService;
// given step
@Before
public void setup() throws IOException {
// must be called for the @Mock annotations to be processed and for the mock service to be injected
// into the controller under test.
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(new AddressController()).build();
}
@When("I add a new Address using POST at {string} with JSON:")
public void i_add_a_new_Address_using_POST_at_with_JSON(String request, String json) throws Exception {
/** Build a POST request using mockMvc **/
result = this.mockMvc.perform(post(request).contentType(MediaType.APPLICATION_JSON)
.content(json.getBytes()).characterEncoding("utf-8"));
}
@Then("the response code should be OK {int} and the resulting json should be:")
public void the_response_code_should_be_OK_and_the_resulting_json_should_be(Integer responseCode,
String json) throws Exception {
result.andExpect(status().is(responseCode));
result.andExpect(content().string(json));
}
@When("I request to view an Address with id {int} at {string}")
public void i_request_to_view_an_Address_with_id_at(Integer id, String request) throws Exception {
/** Build a GET request **/
result = this.mockMvc.perform(get(request + id).contentType(MediaType.APPLICATION_JSON));
}
答案 0 :(得分:1)
假设您使用的是Spring Boot的最新版本(并且您为此还不需要Cucumber),那么您只需使用AddressStepDefs
,即可:
@WebMvcTest(AddressController.class)
public class AddressStepDefs {
@MockBean
private AddressDataManager addressService;
@Autowired
private MockMvc mvc;
...
// Depending on how you configured your Spring beans, you might need this; try first without it ;)
@Configuration
@ComponentScan(basePackageClasses = AddressController.class)
static class TestConfig {
// ...will be used instead of the application's primary configuration
}
}
@WebMvcTest
注释在这里适合您的用例,因为它仅用于仅关注Spring MVC组件的Spring MVC测试。
那么给定的测试可以这样写:
@Test
void getAll_WhenRecordsExist() throws Exception { // HTTP 200 (OK)
final Collection<Address> expected = Arrays.asList(AddressFactory.random(), AddressFactory.random());
Mockito.when(addressService.searchAll()).thenReturn(expected);
mvc.perform(get("/addresses").accept(MediaType.APPLICATION_JSON))
// .andDo(MockMvcResultHandlers.print())
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk())
.andExpect(content().json(mapper.writeValueAsString(expected))); // ...you need Jackson's object mapper injected also as part of a class' member
Mockito.verify(service).searchAll();
}
如果您在嘲笑
addressService
,这不是集成测试,恕我直言。