Вопрос

впервые постер и сторонник TDD.:-) Я буду немного многословен, так что, пожалуйста, потерпите.

Недавно я начал разрабатывать веб-сервисы на основе SOAP, используя среду Apache CXF, Spring и Commons Chain для реализации бизнес-потоков.Проблема, с которой я здесь сталкиваюсь, связана с тестированием веб-сервисов - тестированием, как при модульном тестировании, так и при функциональном тестировании.

Моя первая попытка модульного тестирования закончилась полным провалом.Чтобы обеспечить гибкость модульных тестов, я использовал XML-файл Spring для хранения тестовых данных.Кроме того, вместо того, чтобы создавать экземпляры «компонентов» для тестирования, я извлек их из контекста приложения Spring.Файлы XML, содержащие данные, быстро вышли из-под контроля;создание графов объектов в XML оказалось кошмаром.Поскольку «компоненты», подлежащие тестированию, были выбраны из контекста приложения Spring, каждый запуск теста загружался все компоненты, задействованные в моем приложении, используемые объекты DAO и т. д.Кроме того, в отличие от концепции централизованного или сосредоточенного на тестировании только компонента модульного тестирования, мои модульные тесты начали затрагивать базы данных, взаимодействовать с почтовыми серверами и т. д.Плохо, очень плохо.

Я понял, что сделал не так, и начал думать, как это исправить.Следуя совету из одного из постов на этой доске, я нашел Mockito, фреймворк для имитации Java, чтобы можно было отказаться от использования реальных классов DAO и почтовых серверов и просто поглумиться над функциональностью.

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

public class PaymentScheduleRetrievalComponent implements Command {
  public boolean execute(Context ctx) {
    Policy policy = (Policy)ctx.get("POLICY");
    List<PaymentSchedule> list = billingDAO.getPaymentStatementForPolicy(policy);
    ctx.put("PAYMENT_SCHEDULE_LIST", list);
    return false;
  }
}

Большинство моих компонентов следуют одному и тому же маршруту — выбирают объект домена из контекста, обращаются к DAO [здесь мы используем iBatis в качестве преобразователя SQL] и получаем результат.

Итак, теперь вопросы:
- Как проверяются классы DAO, особенно если одна вставка или обновление может оставить базу данных в «нестабильном» состоянии [в случаях, когда, скажем, 3 вставки в разные таблицы фактически образуют одну транзакцию]?
- Каков стандарт де-факто для веб-сервисов функционального тестирования, которые перемещают большой объем данных, т.е.бессмысленные вставки/извлечения из хранилища данных?

Ваш личный опыт/комментарии будут очень признательны.Пожалуйста, дайте мне знать, если я упустил некоторые детали с моей стороны при объяснении возникшей проблемы.

-Саске

Это было полезно?

Решение

Я бы порекомендовал базу данных в памяти для запуска модульных тестов, например HSQL.Вы можете использовать это для создания схемы на лету (например, если вы используете Hibernate, вы можете использовать файлы сопоставлений XML), а затем вставлять/обновлять/удалять по мере необходимости перед уничтожением базы данных в конце модульного теста.Ваш тест ни при каких обстоятельствах не повлияет на вашу реальную базу данных.

Что касается второй проблемы (сквозное тестирование веб-сервисов): в прошлом я успешно тестировал сервисы на основе CXF.Хитрость заключается в том, чтобы опубликовать ваш веб-сервис с помощью легкого веб-сервера в начале вашего теста (Jetty идеален), затем использовать CXF, чтобы указать клиенту конечную точку вашего веб-сервиса, выполнить вызовы и, наконец, закрыть Jetty. экземпляр, на котором будет размещен ваш веб-сервис после завершения модульного теста.

Чтобы добиться этого, вы можете использовать классы JaxWsServerFactoryBean (на стороне сервера) и JaxWsProxyFactoryBean (на стороне клиента), поставляемые с CXF, пример кода см. на этой странице:

http://cwiki.apache.org/CXF20DOC/a-simple-jax-ws-service.html#AsimpleJAX-WSservice-Publishingyourservice

Я бы также высоко оценил пользовательский интерфейс SOAP для функционального тестирования вашего веб-сервиса.JMeter также чрезвычайно полезен для стресс-тестирования веб-сервисов, что особенно важно для тех сервисов, которые выполняют поиск в базе данных.

Другие советы

На вашем месте я бы держался подальше от шаблона «Контекст как глобальная хэш-карта».

Похоже, вы тестируете свое отображение персистентности...

Возможно, вы захотите взглянуть на: тестирование постоянных объектов без пружины

Прежде всего:Есть ли причина, по которой вам нужно получить тестируемый объект (SUT) из контекста приложения Spring?Для эффективного модульного тестирования вы должны иметь возможность создавать SUT без контекста.Похоже, у вас где-то есть какие-то скрытые зависимости.Это может быть причиной вашей головной боли.

Как классы DAO тестируются ESP, когда одна вставка или обновление могут оставить базу данных в «нестабильном» состоянии [в тех случаях, когда скажем, 3 вставки в разные таблицы фактически образуют одну транзакцию]?

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

  1. Помечайте все свои поддельные данные каким-нибудь общим идентификатором, например, добавляя к полю специальный префикс.
  2. Перед запуском теста добавьте оператор удаления, который удаляет помеченные данные.Если его нет, то ничего страшного не происходит.
  3. Запустите одиночный тест DAO.После этого повторите шаг 2.для следующего теста.

Каков стандарт DE-FACTO для веб-сервисов функционального тестирования, которые перемещаются вокруг множества данных, т.е.Бессмысленные вставки/поиск из хранилища данных?

Я ничего не знаю.Из вопроса, который вы задаете, я могу сделать вывод, что с одной стороны у вас есть веб-сервис, а с другой — база данных.Разделите обязанности.Имейте отдельные наборы тестов для каждой стороны.Одна сторона просто тестирует доступ к базе данных (как описано выше).С другой стороны, просто тестируем запросы и ответы веб-сервисов.В этом случае платит заглушка/подделка/макет уровня, обращающегося к сети.Или рассмотрим https://wsunit.dev.java.net/.

Если программа только вводит и выводит данные, я думаю, что поведение невелико.Если это так, то самая сложная работа — это модульное тестирование стороны базы данных и стороны веб-сервиса.Дело в том, что вы можете проводить модульное тестирование без необходимости получения «реалистичных» данных.Для функционального тестирования вам потребуются данные, собранные вручную и приближенные к реальности.Это может быть обременительно, но если вы уже интенсивно тестировали части базы данных и веб-сервисов, это должно значительно снизить потребность в «реалистичных» тестовых примерах.

Прежде всего, проясните ситуацию.

В идеальном мире жизненный цикл создаваемого вами программного обеспечения выглядит примерно так:- SY делает отчет с клиентом, поэтому вы получили пользовательную историю с примерами о том, как должно работать приложение - вы обобщаете историю пользователя, поэтому вы получили правила, которые вы называете в качестве вариантов использования - вы начинаете писать часть функциональной (конец к концу) тест, и он не удается ...- после этого вы создаете пользовательский интерфейс и макетируете сервисы, чтобы получить зеленый функциональный тест и спецификацию того, как ваши сервисы должны работать...- Ваша задача состоит в том, чтобы сохранить функциональный тест зеленым, и реализовать услуги пошаговые тесты интеграции и высмеивать зависимости с тем же подходом, пока не достигнете уровня модульных тестов - после этого вы выполняете следующую итерацию со сценариями использования , напишите следующий функциональный тест, и так далее до конца проекта - после этого вы проведете приемные тесты с клиентом, который принимает продукт и много платит

Итак, что мы из этого узнали:

  • Существует множество типов тестов (не путайте их друг с другом)
    • функциональные тесты — для тестирования вариантов использования (ничего не имитировать)
    • интеграционные тесты — для тестирования взаимодействия приложения, компонента, модуля, класса (макет ненужных компонентов)
    • юнит-тесты — для тестирования одного класса изолированно от его окружения (смоки всего)
    • пользовательские приемочные тесты - клиент удостоверяется, что он принимает продукт (ручные функциональные тесты или презентация, сделанная на основе автоматических функциональных тестов в работе)
  • Не нужно тестировать все функциональными тестами и интеграционными тестами, потому что это невозможно.Тестируйте только нужную часть с помощью функциональных и интеграционных тестов и тестируйте все с помощью модульных тестов!Ознакомьтесь с пирамида тестирования.
  • Используйте TDD, это облегчает жизнь!
  • Как классы DAO тестируются ESP, когда одна вставка или обновление могут оставить базу данных в «нестабильном» состоянии [в тех случаях, когда скажем, 3 вставки в разные таблицы фактически образуют одну транзакцию]?

Вам не нужно тестировать транзакции базы данных.Предположим, что они работают хорошо, потому что разработчики баз данных их уже протестировали, и я уверен, что вы не хотите писать тесты параллелизма...БД — это внешний компонент, поэтому вам не нужно тестировать его самостоятельно.Вы можете написать уровень доступа к данным, чтобы адаптировать хранилище данных к вашей системе, и написать интеграционные тесты только для этих адаптеров.В случае миграции базы данных эти тесты будут работать и с адаптерами новой базы данных, поскольку вы пишете их для реализации определенного интерфейса...Любыми другими тестами (кроме функциональных тестов) вы можете макетировать свой уровень доступа к данным.Сделайте то же самое со всеми остальными внешними компонентами, напишите адаптеры и макетируйте их.Поместите эти виды интеграционных тестов в другой набор тестов, чем другие тесты, поскольку они медленны из-за доступа к базе данных, доступа к файловой системе и т. д.

  • Каков стандарт де-факто для веб-сервисов функционального тестирования, которые перемещают большой объем данных, т.е.Бессмысленные вставки/поиск из хранилища данных?

Вы можете макетировать свое хранилище данных с помощью базы данных в памяти, которая реализует те же адаптеры хранения, пока вы не реализуете все остальное, кроме базы данных.После этого вы реализуете уровень доступа к данным для базы данных и также тестируете его с помощью функциональных тестов.Это будет медленно, но его нужно запускать только один раз, например, в каждом новом выпуске...Если при разработке вам нужны функциональные тесты, вы можете снова смоделировать их с помощью решения в памяти...Альтернативный подход для запуска только затронутых функциональных тестов путем разработки или изменения настроек тестовой базы данных, чтобы ускорить работу, и так далее...Я уверен, что существует множество решений по оптимизации тестирования...

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

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

Для эффективного модульного тестирования вы должны иметь возможность создавать SUT без контекста.Похоже, у вас где -то есть скрытые зависимости.Это может быть корнем от вашей головной боли.

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

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

Это действительно одно из решений проблемы, о которой я упоминал в своем предыдущем посте, но это может работать не во всех случаях, особенно при интеграции с устаревшей системой, в которой база данных/данные не находятся под вашим контролем, а также в тех случаях, когда некоторые DAO методы требуют, чтобы определенные данные уже присутствовали в данном наборе таблиц.Стоит ли мне изучить среды модульного тестирования баз данных, такие как DBUnit?

В этом случае он оплачивает заглушку/подделку/издеваться над уровнем, разговаривающим с сетью.Или рассмотрим https://wsunit.dev.java.net/.

Ах, выглядит интересно.Я также слышал о таких инструментах, как SOAPUI и ему подобных, которые можно использовать для функционального тестирования.Кто-нибудь здесь добился успеха с такими инструментами?

Спасибо за все ответы и извините за двусмысленное объяснение;Английский не мой родной язык.

-Саске

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top