Spring Framework TEST RESTful Web Service (Controller) Оффлайн i.e Нет сервера, нет базы данных
У меня очень простой RESTful контроллер, который потребляет и производит JSON. Мне нужно протестировать этот контроллер в автономном режиме, т.е. Нет сервера, без работы базы данных. И я схожу с ума, потому что не могу найти решение. Мои основные тесты будут включать:
- Тестирование REST URI, то есть GET, POST, PUT, DELETE - я должен иметь возможность утверждать данные, возвращенные в отношении отправленных данных.
- Assert проверит данные JSON
У меня есть следующие URI:
- /pcusers - возвращает всех пользователей
- /pcusers/{id} - возврат определенного пользователя
- /pcusers/create/{pcuser} - Добавить пользователя в db
- /pcusers/update/{pcuser} - обновить пользователя
- /pcusers/delete/{id} - Удалить пользователя
ПРИМЕЧАНИЕ. Это НЕ типичное приложение MVC. У меня нет просмотров. У меня есть чистый контроллер REST, который выплевывает JSON и потребляет данные в формате JSON.
Если бы кто-то мог вести меня в правильном направлении, это было бы действительно оценено.
Просто чтобы понять, как выглядит мой код:
@Controller
@RequestMapping("/pcusers")
public class PcUserController {
protected static Logger logger = Logger.getLogger(PcUserController.class);
@Resource(name = "pcUserService")
private PcUserService pcUserService;
@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public List<PcUser> readAll() {
logger.debug("Delegating to service to return all PcUsers");
return pcUserService.readAll();
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET, consumes = "application/json", produces = "application/json")
@ResponseBody
public PcUser read(@PathVariable String id) {
logger.debug("Delegating to service to return PcUser " + id);
return pcUserService.read(id);
}
@RequestMapping(value = "/create/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@ResponseBody
public boolean create(@PathVariable PcUser pcUser) {
logger.debug("Delegating to service to create new PcUser");
return pcUserService.create(pcUser);
}
@RequestMapping(value = "/update/{pcUser}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@ResponseBody
public boolean update(@PathVariable PcUser pcUser) {
logger.debug("Delegating to service to update existing PcUser");
return pcUserService.update(pcUser);
}
@RequestMapping(value = "/delete/{id}", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@ResponseBody
public boolean delete(@PathVariable String id) {
logger.debug("Delegating to service to delete existing PcUser");
return pcUserService.delete(id);
}
}
ОБНОВЛЕНИЕ (5/5/2012):
После некоторых исследований я столкнулся с Spring фреймворком spring -test-mvc. Это выглядит очень многообещающе, и мне удалось хорошо начать с этого. Но теперь у меня новая проблема. Когда я отправляю запрос GET на "/pcusers/{id}", элемент управления передается методу read, который отвечает за обработку этого сопоставления. Внутри этого метода у меня есть pcUserService, который читает. Теперь проблема заключается в том, когда я запускаю этот тест, экземпляр pcUserService внутри реального контроллера равен NULL; и поэтому он заканчивается сбоем, поскольку чтение не может быть вызвано на объект NULL.
Здесь Код PcUserControllerTest:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/applicationContextTest.xml")
public class PcUserControllerTest {
@Autowired
PcUserService pcUserService;
@Autowired
PcUserController pcUserController;
PcUser pcUser;
@Before
public void setUp() throws Exception {
pcUser = new PcUser("John", "Li", "Weasley", "john", "john", new DateTime());
pcUserService.create(pcUser);
}
public void tearDown() throws Exception {
pcUserService.delete(pcUser.getId());
}
@Test
public void shouldGetPcUser() throws Exception {
standaloneSetup(pcUserController)
.build()
.perform(get("/pcusers/" + pcUser.getId()).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
Ответы
Ответ 1
Вот одно предложение, которое должно дать вам некоторые идеи. Я предполагаю, что вы знакомы с SpringJUnit4ClassRunner
и @ContextConfiguration
. Начните с создания контекста тестового приложения, содержащего PcUserController
и издевавшегося PcUserService
. В приведенном ниже примере PcUserControllerTest
класс Jackson используется для преобразования сообщений JSON, а Mockito используется для издевательств.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(/* Insert test application context here */)
public class PcUserControllerTest {
MockHttpServletRequest requestMock;
MockHttpServletResponse responseMock;
AnnotationMethodHandlerAdapter handlerAdapter;
ObjectMapper mapper;
PcUser pcUser;
@Autowired
PcUserController pcUserController;
@Autowired
PcUserService pcUserServiceMock;
@Before
public void setUp() {
requestMock = new MockHttpServletRequest();
requestMock.setContentType(MediaType.APPLICATION_JSON_VALUE);
requestMock.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
responseMock = new MockHttpServletResponse();
handlerAdapter = new AnnotationMethodHandlerAdapter();
HttpMessageConverter[] messageConverters = {new MappingJacksonHttpMessageConverter()};
handlerAdapter.setMessageConverters(messageConverters);
mapper = new ObjectMapper();
pcUser = new PcUser(...);
reset(pcUserServiceMock);
}
}
Теперь у нас есть весь код, необходимый для создания тестов:
@Test
public void shouldGetUser() throws Exception {
requestMock.setMethod("GET");
requestMock.setRequestURI("/pcusers/1");
when(pcUserServiceMock.read(1)).thenReturn(pcUser);
handlerAdapter.handle(requestMock, responseMock, pcUserController);
assertThat(responseMock.getStatus(), is(HttpStatus.SC_OK));
PcUser actualPcUser = mapper.readValue(responseMock.getContentAsString(), PcUser.class);
assertThat(actualPcUser, is(pcUser));
}
@Test
public void shouldCreateUser() throws Exception {
requestMock.setMethod("POST");
requestMock.setRequestURI("/pcusers/create/1");
String jsonPcUser = mapper.writeValueAsString(pcUser);
requestMock.setContent(jsonPcUser.getBytes());
handlerAdapter.handle(requestMock, responseMock, pcUserController);
verify(pcUserServiceMock).create(pcUser);
}