Тестируете веб-службу JAX-RS?

84

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

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

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

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

Эйнар
источник
6
Хороший вопрос - однако я бы сказал, что если вы тестируете через HTTP, мне кажется, что это интеграционное тестирование.
Том Дакеринг
Том. Вы абсолютно правы. Для этого мы должны внедрить фиктивный эмулятор HTTP / легкий контейнер. В node.js мир супертест делает это. Вы можете подражать express.js.
Fırat KÜÇÜK

Ответы:

34

В Jersey есть отличный клиентский API RESTful, который упрощает написание модульных тестов. См. Модульные тесты в примерах, поставляемых с Jersey. Мы используем этот подход для тестирования поддержки REST в Apache Camel , если вам интересно, тестовые примеры здесь

Джеймс Страчан
источник
6
re: now bad link Вы можете найти примеры, упомянутые в jersey / samples, которые показывают модульные тесты, в основном используя потребителей jersey для использования веб-ресурсов. download.java.net/maven/2/com/sun/jersey/samples/bookstore/…
rogerdpack
2
Этот проект находится на GitHub, тесты находятся в папке src / test: github.com/jersey/jersey/tree/master/examples/bookstore-webapp
Venkat
2
Я не сомневаюсь в этом ответе, но мне кажется невероятно забавным, что Джерси всегда вступает в разговор о JAX-RS, когда в некоторых случаях (к сожалению, WebSphere) он недоступен и отображает 99% всех приемлемых ответов. о переполнении стека не имеет юридической силы.
26

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

Йохан
источник
1
Я проголосовал за ваш пост, потому что библиотека выглядела хорошо, но они определенно используют много зависимых jar-файлов ...
Перри Тью
18

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

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

...
<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);
    }
}

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

Fırat KÜÇÜK
источник
В Jersey 2.29.1 мне пришлось добавить jersey-hk2в качестве зависимости, потому что я получал java.lang.IllegalStateException: InjectionManagerFactoryошибку «не найдено» (см. Этот вопрос ). В остальном этот пример работает хорошо.
Sarah N
7

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

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

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

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

Entzik
источник
2
Вы совершенно правы, хотя мне также нужно проверить фактические возвращаемые HTTP-ответы, в частности, коды состояния HTTP.
Эйнар
6

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

Билл Ящерица
источник
У вас есть хороший пример имитации обработчиков вызовов? JerseyHttpCall -> MyResource -> CallHandler.getSomething () Как мы можем здесь имитировать CallHandler?
Баладжи Боггарам Раманараян
3

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

Крис Дейл
источник
3

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

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

Отказ от ответственности: я являюсь автором этой библиотеки.

Ашиш Шинде
источник
2

Будь проще. Взгляните на 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...
Keyoxy
источник
1

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

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

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

REST - это не то, что эта служба может для вас сделать; ОТДЫХАЙТЕ, что вы можете сделать для этой службы.


источник
Люди могут захотеть проверить некоторые общие проблемы. Например, проверка, аутентификация, желаемые заголовки HTTP и т. Д. Таким образом, люди могут предпочесть тестирование своего кода JAX-RS.
Fırat KÜÇÜK
В своем приложении я использую ModelMapper для «сопоставления» классов «DTO» с классами «бизнес-объектов», которые понимаются лежащими в основе «служебными» классами. Это пример того, что неплохо бы самостоятельно протестировать.
jkerak 08
И иногда апплет REST имеет настолько небольшую сложность, что макеты будут больше, чем уровень приложения, как в моем текущем случае. :)
tekHedd
1

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

  1. Запустите тестовый веб-сервер или сервер приложений, поместите в него компоненты JAX RS. И только они.
  2. Имитация бизнес-сервисов внутри компонентов JAX RS / уровня REST.

Первый решается с помощью Аркиллиана. Второй прекрасно описан аркилликанским языком и имитирует

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

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));
   }
}

Пара замечаний:

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

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

Александр
источник
Поддерживается ли этот тип вещей встроенной тестовой платформой? Я просто не решаюсь добавить в свой проект «еще один фреймворк» и все его jar-файлы, если у меня уже есть что-то доступное с Джерси.
jkerak 08