Как использовать mockito для тестирования службы REST?
Я очень новичок в Java Unit Testing, и я слышал, что структура Mockito действительно хороша для тестирования.
Я разработал REST-сервер (CRUD-методы), и теперь я хочу его протестировать, но я не знаю, как?
Более того, я не знаю, как начать эту процедуру тестирования. Мой сервер должен работать на localhost, а затем делать вызовы на этом URL-адресе (например, localhost: 8888)?
Вот что я пробовал до сих пор, но я уверен, что это неправильный путь.
@Test
public void testInitialize() {
RESTfulGeneric rest = mock(RESTfulGeneric.class);
ResponseBuilder builder = Response.status(Response.Status.OK);
builder = Response.status(Response.Status.OK).entity(
"Your schema was succesfully created!");
when(rest.initialize(DatabaseSchema)).thenReturn(builder.build());
String result = rest.initialize(DatabaseSchema).getEntity().toString();
System.out.println("Here: " + result);
assertEquals("Your schema was succesfully created!", result);
}
Вот код для метода initialize
.
@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("/initialize")
public Response initialize(String DatabaseSchema) {
/** Set the LogLevel to Info, severe, warning and info will be written */
LOGGER.setLevel(Level.INFO);
ResponseBuilder builder = Response.status(Response.Status.OK);
LOGGER.info("POST/initialize - Initialize the " + user.getUserEmail()
+ " namespace with a database schema.");
/** Get a handle on the datastore itself */
DatastoreService datastore = DatastoreServiceFactory
.getDatastoreService();
datastore.put(dbSchema);
builder = Response.status(Response.Status.OK).entity(
"Your schema was succesfully created!");
/** Send response */
return builder.build();
}
В этом тестовом примере я хочу отправить строку Json на сервер (POST). Если все пойдет хорошо, сервер должен ответить: "Ваша схема была успешно создана!".
Кто-нибудь может помочь мне?
Ответы
Ответ 1
OK. Итак, контракт метода следующий: проанализируйте входную строку как JSON и отправьте назад BAD_REQUEST
, если она недействительна. Если он действителен, создайте объект в datastore
с различными свойствами (вы их знаете) и отправьте обратно OK
.
И вам нужно убедиться, что этот контракт выполняется методом.
Где Мокито помогает здесь? Ну, если вы протестируете этот метод без Mockito, вам понадобится реальный DataStoreService
, и вам нужно убедиться, что объект был создан правильно в этом реальном DataStoreService
. В этом случае ваш тест уже не является unit test, и это также слишком сложно проверить, слишком долго и слишком сложно запустить, потому что ему нужна сложная среда.
Mockito может помочь, издеваясь над зависимостью от DataStoreService
: вы можете создать макет DataStoreService
и убедиться, что этот макет действительно вызван с соответствующим аргументом объекта, когда вы вызываете ваш метод initialize()
в своем тесте.
Для этого вам нужно будет ввести DataStoreService
в тестируемый объект. Это может быть так же просто, как рефакторинг вашего объекта следующим образом:
public class MyRestService {
private DataStoreService dataStoreService;
// constructor used on the server
public MyRestService() {
this.dataStoreService = DatastoreServiceFactory.getDatastoreService();
}
// constructor used by the unit tests
public MyRestService(DataStoreService dataStoreService) {
this.dataStoreService = dataStoreService;
}
public Response initialize(String DatabaseSchema) {
...
// use this.dataStoreService instead of datastore
}
}
И теперь в вашем тестовом методе вы можете сделать:
@Test
public void testInitializeWithGoodInput() {
DataStoreService mockDataStoreService = mock(DataStoreService.class);
MyRestService service = new MyRestService(mockDataStoreService);
String goodInput = "...";
Response response = service.initialize(goodInput);
assertEquals(Response.Status.OK, response.getStatus());
ArgumentCaptor<Entity> argument = ArgumentCaptor.forClass(Entity.class);
verify(mock).put(argument.capture());
assertEquals("the correct kind", argument.getValue().getKind());
// ... other assertions
}
Ответ 2
То, о чем вы говорите, больше похоже на интеграционное тестирование и Mockito (или любые другие насмешливые фреймворки), не будет вам очень полезен.
Если вы хотите написать код unit test, который вы написали, Mockito, безусловно, полезный инструмент.
Я предлагаю вам больше узнать о насмешливом/модульном тестировании и о том, какие обстоятельства он должен использовать.
Ответ 3
Mockito (обычно) для тестирования частей кода; например, если вы потребляете свой REST-сервис, но не хотите выполнять полный тест стека, вы издеваетесь над сервисом, подключенным к службе REST, что позволяет точно и последовательно тестировать конкретное поведение.
Чтобы протестировать внутренние части службы REST (например, конкретный метод службы) без попадания в базу данных, вы будете издеваться над подсистемой БД, позволяя тестировать только внутренние службы без привлечения БД. Это тестирование принадлежит сервисному модулю REST, а не стороне клиента.
Чтобы протестировать службу REST, вы должны использовать фактическую клиентскую библиотеку, создав тест интеграции с полным стеком. Mockito можно использовать здесь, чтобы высмеять части клиента, не связанные с потреблением службы REST.
Ответ 4
Лучший способ - использовать wiremock. Добавьте следующие зависимости. com.github.tomakehurst wiremock 2.4.1 org.igniterealtime.smack smack-core 4.0.6
Определите и используйте wiremock, как показано ниже
@Rule
public WireMockRule wireMockRule = new WireMockRule(8089);
String response ="Hello world";
StubMapping responseValid = stubFor(get(urlEqualTo(url)).withHeader("Content-Type", equalTo("application/json"))
.willReturn(aResponse().withStatus(200)
.withHeader("Content-Type", "application/json").withBody(response)));
Ответ 5
Я согласен, что это не модульное тестирование, а интеграционный тест, во всяком случае, вы бы лучше взглянули на трикотаж и встроенные тесты сервера гризли. Чтобы суммировать этот код, этот код запускает сервер grizzly (который также может запускать базу данных) на localhost: 8888, а затем настраивает клиентский джерси-клиент и отправляет запрос POST, ответ на который должен быть проверен. Это интеграция, поскольку вы тестируете сервер и базу данных, однако вы можете использовать mockito для эмуляции базы данных, но это зависит от того, насколько привязаны ваш сервер и база данных.
(тест с использованием трикотажа 1.11 и grizzly 2.2)
@BeforeClass
public static void setUpClass() throws Exception {
// starts grizzly
Starter.start_grizzly(true);
Thread.sleep(4000);
}
@Before
public void setUp() throws Exception {
client = new Client();
webResource = client.resource("http://localhost:8888");
}
@Test
public void testPostSchemaDatabase() throws Exception {
{
String DatabaseSchema = "{ database_schema : {...}}";
logger.info("REST client configured to send: " + DatabaseSchema);
ClientResponse response =
webResource
.path("/initialize")
.type("application/json")
.post(ClientResponse.class, DatabaseSchema);
//wait for the server to process
Thread.sleep(2000);
assertEquals(response.getStatus(), 204);
//test the response
}
}
@After
public void after() throws JSONException
{
//probably you want to delete the schema at database and stop the server
}