Тестування веб-служби JAX-RS?


84

Зараз я шукаю способи створення автоматизованих тестів для веб-служби на основі JAX-RS (Java API для RESTful Web Services).

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

Який підхід ви використовуєте для тестування своїх веб-сервісів?

Оновлення: Як зазначив entzik, відокремлення веб-служби від бізнес-логіки дозволяє мені модульно перевірити бізнес-логіку. Однак я також хочу перевірити правильність кодів стану HTTP тощо.


6
Гарне запитання - проте я б сказав, що якщо ви тестуєте через HTTP, мені здається, що це інтеграційне тестування.
Tom Duckering

Том. Ви абсолютно праві. Для цього нам слід ввести фіктивний емулятор HTTP / полегшений контейнер. У світі node.js це робить супертест. Ви можете емулювати express.js.
Fırat KÜÇÜK

Відповіді:


34

Джерсі постачається з чудовим клієнтським API RESTful, що робить написання модульних тестів справді простим. Див. Одиничні тести в прикладах, що постачаються з Джерсі. Ми використовуємо цей підхід для перевірки підтримки REST в Apache Camel , якщо ви зацікавлені, тестові приклади тут


6
re: now bad link Ви можете знайти приклади, згадані у джерсі / зразках, які показують модульні тести, в основному, використовуючи споживачів джерсі для споживання веб-ресурсів. 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 Assured, що робить дуже простим тестування служб REST та перевірку відповіді на Java (за допомогою JUnit або TestNG).


1
Я проголосував за ваш пост, бо бібліотека виглядала добре, але вони, звичайно, використовують багато залежних банок ...
Перрі Тью,

17

Як сказав Джеймс; Існує вбудований тестовий каркас для Джерсі. Простий приклад зі світу може бути таким:

pom.xml для інтеграції maven. Коли ти біжиш mvn test. Фреймворки запускають контейнер гризлі. Ви можете використовувати jetty або 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);
    }
}

Ви можете перевірити цей зразок програми.


З Jersey 2.29.1 мені довелося додати jersey-hk2як залежність, оскільки я отримував java.lang.IllegalStateException: InjectionManagerFactoryпомилку не знайдено (див. Це запитання ). В іншому випадку цей приклад працює добре.
Сара Н

7

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

Важливо зробити самостійне тестування своєї ділової логіки. Оскільки це чистий Java-код, ви можете це зробити за допомогою регулярних тестів JUnit.

Тепер, оскільки частина веб-служб - це лише кінцева точка, ви хочете переконатися, що згенерована сантехніка (заглушки тощо) синхронізується з вашим кодом Java. Ви можете зробити це, написавши тести JUnit, які викликають створені клієнти Java веб-служби. Це дасть вам знати, коли ви змінюєте підписи Java без оновлення матеріалів веб-служб.

Якщо сантехніка ваших веб-служб автоматично генерується вашою системою збірки під час кожної збірки, можливо, не потрібно буде перевіряти кінцеві точки (за умови, що все це правильно створено). Залежить від вашого рівня параної.


2
Ви цілком праві, хоча мені також потрібно перевірити фактичні відповіді HTTP, які повертаються, зокрема коди стану HTTP.
Ейнар,

6

Хоча це занадто пізно з дати публікації запитання, вважав, що це може бути корисно для інших, хто має подібне запитання. Джерсі постачається з тестовою структурою під назвою Джерсі Тестова рамка, яка дозволяє протестувати свою веб-службу 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, використовуючи джерсі-клієнт за кадром. Фактично ви будете називати вас методами веб-сервісу як прості 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...

1

Важливо зробити самостійне тестування своєї ділової логіки

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

Як у Джерсі, так і у RESTEasy є клієнтські програми, а у випадку з RESTEasy ви можете використовувати ті самі анотації (навіть вилучати анотований інтерфейс та використовувати на стороні клієнта та сервера ваших тестів).

ВІДПОЧИНІТЬ не те, що ця послуга може зробити для вас; Відпочиньте, що ви можете зробити для цієї послуги.


Люди можуть захотіти перевірити деякі наскрізні проблеми. Наприклад, перевірка, автентифікація, бажані заголовки HTTP тощо. Тому люди можуть віддати перевагу тестуванню свого коду JAX-RS.
Fırat KÜÇÜK

У моїй програмі я використовую ModelMapper для "зіставлення" класів "DTO" з класами "бізнес-об'єкта", які розуміються під базовими класами "служби". Це приклад чогось, що було б непогано перевірити самостійно.
jkerak

І іноді 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 Client (немає RESTEasy / Jersey, вони надають більш зручний API)
  3. Коли тест починається, бігун Аркіліана починає працювати. Тут ви знайдете, як налаштувати тести для Arquillian з необхідним сервером додатків.
  4. Залежно від обраного сервера додатків, URL-адреса в тесті буде дещо відрізнятися. Може використовуватися інший порт. 8181 використовується Glassfish Embedded у моєму прикладі.

Сподіваюся, це допоможе.


чи підтримується цей тип речей вбудованою структурою тестування джерсі? Я просто вагаюся, щоб додати "ще один фреймворк" та всі його баночки до свого проекту, якщо я вже маю щось із Джерсі.
jkerak
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.