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