Вопрос

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

Например, если у меня есть контроллер HomeController, который должен иметь LoginService введено в него, а затем в мой модульный тест HomeControllerTest Я просто создаю экземпляр объекта как обычно (вне Spring) и внедряю свойство:

protected void setUp() throws Exception {
    super.setUp();
    //...
    controller = new HomeController();
    controller.setLoginService( new SimpleLoginService() );
    //...
}

Это отлично подходит для тестирования каждого компонента как изолированного модуля - за исключением того, что теперь, когда у меня есть несколько десятков классов в проекте, после написания класса и написания успешного модульного теста для него я все время забываю обновить мой контекстный файл Spring MVC, который фактическое подключение в развернутом приложении.Я обнаружил, что забыл обновить файл контекста, когда развертываю проект в Tomcat и нахожу кучу NullPointers из несвязанных bean-компонентов.

Итак, вот мои вопросы:

  1. Это мой первый проект Spring — нормально ли создавать модульные тесты для отдельных bean-компонентов, как я это сделал, а затем создавать второй набор тестов (интеграционные тесты), чтобы проверить, что все работает так, как ожидалось, с реальным контекстом приложения?Существует ли для этого устоявшаяся передовая практика?

  2. Кроме того, как отделить модульные тесты от интеграционных тестов?У меня есть весь исходный код src, модульные тесты в test - должна ли быть вторая тестовая папка (например, test-integration) для тестов интеграции?

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

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

Решение

Я не могу говорить о лучшей практике, но вот что я делал в прошлом.

Модульные тесты:

  • Создайте модульные тесты для нетривиальных bean-компонентов (т. е. большинства ваших bean-компонентов, связанных с Spring).
  • Используйте Mocks для внедряемых сервисов там, где это практически возможно (т. е. большую часть времени, если не всегда).
  • Используйте стандартное соглашение об именах для этих тестов в проекте. test каталог.С использованием Test или TestCase в качестве префикса или суффикса к имени класса, по-видимому, широко практикуется.

Интеграционные тесты:

  • Создать AbstractIntegrationTestCase который устанавливает Spring WebApplicationContext для использования в классах интеграционного тестирования.
  • Используйте соглашение об именах для интеграционных тестов в test каталог.я использовал IntTest или IntegrationTest в качестве префикса или суффикса для этих тестов.

Установите три муравья test цели:

  1. test-all (или как вы хотите его назвать):Запуск модульных и интеграционных тестов
  2. тест:Запускайте модульные тесты (просто потому, что test кажется, наиболее распространенное использование для модульного тестирования
  3. тестовая интеграция:запустить интеграционные тесты.

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

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

Например, последний Java-проект, над которым я работал с Spring, использовал именно то, что описано выше, с интеграционными и модульными тестами, живущими в одном и том же пространстве. test каталог.С другой стороны, проекты Grails явно разделяют каталоги модульных и интеграционных тестов в общем каталоге тестов.

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

Несколько отдельных моментов:

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

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

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

Полезны базовые интеграционные тесты для ознакомления с контекстами Spring.

Аннотация @required может помочь вам убедиться, что вы перехватываете необходимые зависимости в вашей проводке Spring.

Возможно, загляните в Maven, который даст вам четкие этапы привязки вашего модуля и интеграционных тестов. Maven довольно широко используется в сообществе Spring.

Большая часть утомительной двойной бухгалтерии с Spring исчезнет, ​​если вы также перейдете в чисто аннотированный режим, в котором вы аннотируете все свои bean-компоненты с помощью @Component, @Controller, @Service и @Repository.Просто добавьте @Autowired к атрибутам, которые вам нужно внедрить.

См. раздел 3.11 справочного руководства по пружинам. http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config

Кстати, мы использовали тесты Unit/Integratrion, описанные KenG.В моем последнем режиме мы также ввели третий «класс» тестов — «ComponentTests».Они работают с полной пружинной проводкой, но с проводными реализациями заглушки (с использованием фильтров сканирования компонентов и аннотаций в Spring).

Причина, по которой мы это сделали, заключалась в том, что на некоторых слоях «сервисов» вы получаете огромное количество закодированной вручную логики подключения для ручного подключения компонента, а иногда и нелепое количество макетов объектов.100 линий проводки на 5 линий тестирования – не редкость.Компонентные тесты решают эту проблему.

Используйте интерфейс InitializingBean (реализует метод "afterPropertiesSet") или укажите метод init для ваших компонентов. InitializingBean обычно проще, потому что вам не нужно не забывать добавлять метод init к вашим bean-компонентам.

Используйте afterPropertiesSet, чтобы убедиться, что все вводится как ненулевое значение, если оно равно NULL, создайте исключение.

Когда я создал интеграционные тесты для веб-приложений, я поместил их в отдельный каталог. Они построены с использованием jUnit или TestNG и взаимодействуют с тестируемой системой с помощью чего-то вроде Selenium , который попадает на веб-страницы как будто они были пользователями. Цикл будет выглядеть следующим образом: компилировать, запускать модульные тесты, создавать веб-приложение, развертывать его на работающем сервере, выполнять тесты, отменять развертывание приложения и сообщать о результатах. Идея состоит в том, чтобы проверить всю систему.

Что касается запуска модульных тестов отдельно от интеграционных тестов, я поместил все последние в каталог интеграционных тестов и запустил их, используя IDE / Ant, используя такой подход, как этого. У меня работает.

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

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