Единичное тестирование веб-службы JAX-RS?

В настоящее время я ищу способы создания автоматических тестов для веб-службы JAX-RS (Java API для RESTful Web Services).

Мне в основном нужен способ отправить его определенным входам и проверить, что я получаю ожидаемые ответы. Я бы предпочел сделать это через JUnit, но я не уверен, как это можно достичь.

Какой подход вы используете для тестирования своих веб-сервисов?

Обновление: Как отметил энцик, развязка веб-службы из бизнес-логики позволяет мне unit test бизнес-логику. Тем не менее, я также хочу проверить правильные коды состояния HTTP и т.д.

Ответ 1

Jersey поставляется с отличным API-интерфейсом RESTful, который делает тесты модульных записей очень легкими. См. Блок-тесты в примерах, которые поставляются с Джерси. Мы используем этот подход для тестирования поддержки REST в Apache Camel, если вам интересно здесь >

Ответ 2

Вы можете опробовать REST Assured, что позволяет очень просто тестировать службы REST и проверять ответ на Java (используя JUnit или TestNG).

Ответ 3

Как сказал Джеймс; Существует встроенная тестовая среда для Джерси. Пример простого приветствия может быть таким:

pom.xml для интеграции maven. Когда вы запустите mvn test. Рамки запускают контейнер гризли. Вы можете использовать причал или tomcat через изменения зависимостей.

...
<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.16</version>
  </dependency>

  <dependency>
    <groupId>org.glassfish.jersey.test-framework</groupId>
    <artifactId>jersey-test-framework-core</artifactId>
    <version>2.16</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.16</version>
    <scope>test</scope>
  </dependency>
</dependencies>
...

ExampleApp.java

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
public class ExampleApp extends Application {

}

HelloWorld.java

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/")
public final class HelloWorld {

    @GET
    @Path("/hello")
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHelloWorld() {

        return "Hello World!";
    }
}

HelloWorldTest.java

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.core.Application;
import static org.junit.Assert.assertEquals;

public class HelloWorldTest extends JerseyTest {

    @Test
    public void testSayHello() {

        final String hello = target("hello").request().get(String.class);

        assertEquals("Hello World!", hello);
    }

    @Override
    protected Application configure() {

        return new ResourceConfig(HelloWorld.class);
    }
}

Вы можете проверить это пример приложения.

Ответ 4

Хотя его слишком поздно с даты публикации вопроса, подумал, что это может быть полезно для других, у кого есть аналогичный вопрос. Джерси поставляется с тестовой платформой, называемой Jersey Test Framework, которая позволяет вам тестировать веб-службу RESTful, включая коды статуса ответа. Вы можете использовать его для запуска тестов на легких контейнерах, таких как Grizzly, HTTPServer и/или EmbeddedGlassFish. Кроме того, фрейм может использоваться для запуска ваших тестов на обычном веб-контейнере, таком как GlassFish или Tomcat.

Ответ 5

Вероятно, вы написали некоторый Java-код, который реализует вашу бизнес-логику, а затем вы создали конечную точку веб-служб для него.

Важная вещь, которую нужно сделать, - это самостоятельно протестировать свою бизнес-логику. Поскольку это чистый код Java, вы можете сделать это с помощью обычных тестов JUnit.

Теперь, поскольку часть веб-сервисов является лишь конечной точкой, вы должны убедиться, что созданная сантехника (заглушки и т.д.) синхронизируется с вашим java-кодом. вы можете это сделать, написав тесты JUnit, которые вызывают созданные Java-клиенты веб-сервисов. Это позволит вам узнать, когда вы меняете свои подписи java, не обновляя материал веб-сервисов.

Если ваша система веб-сервисов автоматически генерируется вашей системой сборки при каждой сборке, тогда может быть необязательно проверять конечные точки (при условии, что все это правильно сгенерировано). Зависит от вашего уровня паранойи.

Ответ 6

Я использую Apache HTTPClient (http://hc.apache.org/) для вызова Restful Services. Библиотека HTTP Client позволяет вам легко выполнять получение, публикацию или любую другую операцию, в которой вы нуждаетесь. Если ваша служба использует JAXB для привязки xml, вы можете создать JAXBContext для сериализации и десериализации входов и выходов из HTTP-запроса.

Ответ 7

Посмотрите генератор поколений алхимиков. Это может привести к реализации прокси для вашего веб-сервиса JAX-RS, используя jersey-клиент за сценой. Эффективно вы будете называть вас методами webservice как простые java-методы из ваших модульных тестов. Также обрабатывает HTTP-аутентификацию.

Не требуется генерация кода, если вам нужно просто запускать тесты, чтобы это было удобно.

Dislclaimer: Я являюсь автором этой библиотеки.

Ответ 8

Важная вещь, которую нужно сделать, это самостоятельно протестировать свою бизнес-логику

Я, конечно, не стал бы предполагать, что человек, который написал код JAX-RS и ищет интерфейс unit test, каким-то образом, по какой-то странной необъяснимой причине, не обращает внимания на то, что он или она может тестировать другие части программы, включая классы бизнес-логики. Нехорошо было заявить очевидное, и неоднократно подчеркивалось, что ответы также должны быть проверены.

И у Джерси, и у RESTEasy есть клиентские приложения, и в случае RESTEasy вы можете использовать те же аннотации (даже выставлять аннотированный интерфейс и использовать на клиентской и серверной стороне ваших тестов).

REST не то, что эта услуга может сделать для вас; REST, что вы можете сделать для этой услуги.

Ответ 9

Держите его простым. Посмотрите https://github.com/valid4j/http-matchers, который можно импортировать из Maven Central.

    <dependency>
        <groupId>org.valid4j</groupId>
        <artifactId>http-matchers</artifactId>
        <version>1.0</version>
    </dependency>

Пример использования:

// Statically import the library entry point:
import static org.valid4j.matchers.http.HttpResponseMatchers.*;

// Invoke your web service using plain JAX-RS. E.g:
Client client = ClientBuilder.newClient();
Response response = client.target("http://example.org/hello").request("text/plain").get();

// Verify the response
assertThat(response, hasStatus(Status.OK));
assertThat(response, hasHeader("Content-Encoding", equalTo("gzip")));
assertThat(response, hasEntity(equalTo("content")));
// etc...

Ответ 10

Насколько я понимаю, основной целью автора этой проблемы является отключение уровня JAX RS от бизнес-интерфейса. И unit test только первый. Здесь мы должны решить две основные проблемы:

  • Запустите в тестовом режиме веб-сервер/сервер приложений, добавьте компоненты JAX RS в Это. И только они.
  • Управление бизнес-сервисами внутри JAX RS компонентов /REST.

Первая решена с Аркиллиан. Второй вариант прекрасно описан в arquillican и mock

Вот пример кода, он может отличаться, если вы используете другой сервер приложений, но я надеюсь, что вы получите основную идею и преимущества.

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.brandmaker.skinning.service.SomeBean;

/**
* Created by alexandr on 31.07.15.
*/
@Path("/entities")
public class RestBean
{
   @Inject
   SomeBean bean;

   @GET
   public String getEntiry()
   {
       return bean.methodToBeMoked();
   }
}

import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

import com.google.common.collect.Sets;

/**
*/
@ApplicationPath("res")
public class JAXRSConfiguration extends Application
{
   @Override
   public Set<Class<?>> getClasses()
   {
       return Sets.newHashSet(RestBean.class);
   }
}


public class SomeBean
{
   public String methodToBeMoked()
   {
       return "Original";
   }
}

import javax.enterprise.inject.Specializes;

import com.brandmaker.skinning.service.SomeBean;

/**
*/
@Specializes
public class SomeBeanMock extends SomeBean
{
   @Override
   public String methodToBeMoked()
   {
       return "Mocked";
   }
}

@RunWith(Arquillian.class)
public class RestBeanTest
{
   @Deployment
   public static WebArchive createDeployment() {
       WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
               .addClasses(JAXRSConfiguration.class, RestBean.class, SomeBean.class, SomeBeanMock.class)
               .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
       System.out.println(war.toString(true));
       return war;
   }

   @Test
   public void should_create_greeting() {
       Client client = ClientBuilder.newClient();
       WebTarget target = client.target("http://127.0.0.1:8181/test/res/entities");
       //Building the request i.e a GET request to the RESTful Webservice defined
       //by the URI in the WebTarget instance.
       Invocation invocation = target.request().buildGet();
       //Invoking the request to the RESTful API and capturing the Response.
       Response response = invocation.invoke();
       //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
       //into the instance of Books by using JAXB.
       Assert.assertEquals("Mocked", response.readEntity(String.class));
   }
}

Несколько примечаний:

  • Конфигурация JAX RS без web.xml используется здесь.
  • Клиент JAX RS используется здесь (нет RESTEasy/Jersey, они предоставляют более удобный API)
  • Когда начнется тест, начинает работать аркиллианский бегун. Здесь вы можете найти, как настроить тесты для Arquillian с необходимым сервером приложений.
  • В зависимости от выбранного сервера приложений, URL-адрес тест будет немного отличаться. Может использоваться другой порт. 8181 - используемый Glassfish Embedded в моем примере.

Надеюсь, это поможет.