Подтвердить что ты не робот

Как использовать 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). Если все пойдет хорошо, сервер должен ответить: "Ваша схема была успешно создана!".

Кто-нибудь может помочь мне?

4b9b3361

Ответ 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

}