Небольшой блог на тему, которую я обсуждал на прошлой неделе с клиентом:
тестирование веб-сервисов 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 и поэтому не переносим.