Статьи

Вам не нужно издеваться над своей веб-службой SOAP, чтобы проверить


Небольшой блог на тему, которую я обсуждал на прошлой неделе с клиентом:
тестирование веб-сервисов SOAP . Если вы будете следить за моим блогом, вы уже знаете, что я не фанат модульного тестирования в среде MOCK. Не потому, что мне это не нравится или у меня есть религиозные убеждения, которые не позволяют мне использовать
JUnit  и
Mockito . Это просто потому, что с работой, которую я выполняю (в основном
Java EE с использованием серверов приложений), мой код выполняется в управляемой среде (т.е. контейнерах), и когда я начинаю насмехаться над всеми службами контейнера, он становится громоздким и бесполезным. Несколько месяцев назад я написал пост об
интеграционном тестировании с Arquillian . Но тебе не всегда нужен
Аркиллиандля тестирования внутри контейнера, потому что сегодня большинство контейнеров легкие и работают в памяти. Подумайте о базе данных в памяти. Веб-контейнер в памяти. Контейнер EJB в памяти
.

Итак, во-первых, давайте напишем веб-сервис SOAP. Я использую тот, который я использую в своей книге : веб-сервис SOAP, который проверяет кредитную карту. Если вы посмотрите на код, в нем нет ничего особенного (алгоритм проверки кредитной карты является фиктивным: четные числа действительны, нечетные недействительны). Начнем с интерфейса:

import javax.jws.WebService;

@WebService
public interface Validator {
    public boolean validate(CreditCard creditCard);
}

Затем реализация SOAP Web Service:

@WebService(endpointInterface = "org.agoncal.book.javaee7.chapter21.Validator")
public class CardValidator implements Validator {

  public boolean validate(CreditCard creditCard) {

    Character lastDigit = creditCard.getNumber().charAt(creditCard.getNumber().length() - 1);

    return Integer.parseInt(lastDigit.toString()) % 2 != 0;
  }
}

В этом модульном тесте я создаю экземпляр класса CardValidator и вызываю метод validate. Это приемлемо, но что если ваша SOAP Web Serivce использует обработчики ? Что если он переопределяет сопоставление с помощью дескриптора развертывания webservice.xml? Использует WebServiceContext ? Короче говоря, что если ваша веб-служба SOAP использует службы контейнеров? Модульное тестирование становится бесполезным. Итак, давайте проверим вашу веб-службу SOAP внутри контейнера и напишем интеграционный тест. Для этого мы можем использовать веб-контейнер в памяти. И я говорю не только о GlassFish, JBoss или Tomcat, но о чем-то столь же простом, как веб-контейнер, который поставляется с JDK SUN. Внедрение Sun Java SE 6 включает в себя  облегченный  API-интерфейс HTTP-сервера и реализацию:  com.sun.net.httpserver,

Обратите внимание, что этот HTTP-сервер по умолчанию находится в пакете com.sun. Так что это может быть не переносимым в зависимости от версии вашего JDK. Вместо использования HTTP-сервера по умолчанию можно также подключить другие реализации, если они предоставляют  реализацию поставщика услуг  (SPI), например J2se6HttpServerSPI Jetty .

Вот как может выглядеть интеграционный тест с использованием веб-контейнера в памяти:

public class CardValidatorIT {

  @Test
  public void shouldCheckCreditCardValidity() throws MalformedURLException {
    // Publishes the SOAP Web Service
    Endpoint endpoint = Endpoint.publish("http://localhost:8080/cardValidator", new CardValidator());
    assertTrue(endpoint.isPublished());
    assertEquals("http://schemas.xmlsoap.org/wsdl/soap/http", endpoint.getBinding().getBindingID());

    // Data to access the web service
    URL wsdlDocumentLocation = new URL("http://localhost:8080/cardValidator?wsdl");
    String namespaceURI = "http://chapter21.javaee7.book.agoncal.org/";
    String servicePart = "CardValidatorService";
    String portName = "CardValidatorPort";
    QName serviceQN = new QName(namespaceURI, servicePart);
    QName portQN = new QName(namespaceURI, portName);

    // Creates a service instance
    Service service = Service.create(wsdlDocumentLocation, serviceQN);
    Validator cardValidator = service.getPort(portQN, Validator.class);

    // Invokes the web service
    CreditCard creditCard = new CreditCard("12341234", "10/10", 1234, "VISA");

    assertFalse("Credit card should be valid", cardValidator.validate(creditCard));
    creditCard.setNumber("12341233");
    assertTrue("Credit card should not be valid", cardValidator.validate(creditCard));

    // Unpublishes the SOAP Web Service
    endpoint.stop();
    assertFalse(endpoint.isPublished());
  }
}

Метод Endpoint.publish () по умолчанию использует облегченную реализацию HTTP-сервера, которая включена в Sun SE SE 6. Он публикует веб-службу SOAP и начинает прослушивать URL-адрес http: // localhost: 8080 / cardValidator. Вы даже можете перейти на http: // localhost: 8080 / cardValidator? Wsdl, чтобы увидеть сгенерированный WSDL. Тест интеграции ищет документ WSDL, создает службу с использованием информации WSDL, получает порт для веб-службы SOAP и затем вызывает метод validate. Метод Endpoint.stop () останавливает публикацию службы и закрывает веб-сервер в памяти.

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