Веб-интеграционные тесты позволяют проводить интеграционное тестирование приложения Spring Boot без каких-либо насмешек. Используя @WebIntegrationTest и @SpringApplicationConfiguration мы можем создавать тесты, которые загружают приложение и прослушивают обычные порты. Это небольшое дополнение к Spring Boot значительно упрощает создание интеграционных тестов с Selenium WebDriver.
Тест Зависимости
Приложение, которое мы будем тестировать, представляет собой простое приложение Spring Boot / Thymeleaf с зависимостями spring-boot-starter-web , spring-boot-starter-thymeleaf и spring-boot-starter-actuator spring-boot-starter-thymeleaf . Смотрите ссылки для ссылки на проект GitHub.
Тестовые зависимости:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency><dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>1.5.0</version> <scope>test</scope></dependency><dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.45.0</version> <scope>test</scope></dependency> |
Тест веб-интеграции
С классическим Spring Test, используя MockMvc , вы создали бы тест, как MockMvc ниже:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = Application.class)@WebAppConfigurationpublic class HomeControllerClassicTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setUp() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test public void verifiesHomePageLoads() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/")) .andExpect(MockMvcResultMatchers.status().isOk()); }} |
@SpringApplicationConfiguration расширяет возможности @ContextConfiguration и загружает контекст приложения для интеграционного теста. Чтобы создать тест без смоделированной среды, мы должны определить наш тест, используя аннотацию @WebIntegrationTest :
|
1
2
3
4
5
6
|
@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = Application.class)@WebIntegrationTest(value = "server.port=9000")public class HomeControllerTest {} |
Это запустит полное приложение в тесте JUnit, прослушивая порт 9000 . Имея такой тест, мы можем легко добавить Selenium и выполнить реальные функциональные тесты с помощью браузера (не будет работать в автономной среде, если мы не используем драйвер HtmlUnit — но это выходит за рамки этой статьи).
Добавление селена
Добавить Selenium к тесту очень просто, но я хотел достичь немного большего, поэтому я создал собственную аннотацию, чтобы пометить свои тесты как тесты Selenium. Я также настроил его так, чтобы он позволял внедрять WebDriver в тестовый экземпляр:
|
01
02
03
04
05
06
07
08
09
10
|
@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = Application.class)@WebIntegrationTest(value = "server.port=9000")public class HomeControllerTest { @Autowired private WebDriver driver;} |
@SeleniumTest
@SeleniumTest — это пользовательская аннотация:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@TestExecutionListeners( listeners = SeleniumTestExecutionListener.class, mergeMode = MERGE_WITH_DEFAULTS)public @interface SeleniumTest { Class<? extends WebDriver> driver() default FirefoxDriver.class;} |
В аннотации используется прослушиватель выполнения теста, который создаст экземпляр WebDriver который можно использовать в интеграционном тесте. TestExecutionListener определяет API слушателя для реакции на события выполнения теста. Это может быть использовано для тестирования инструментов. Примеры реализации в Spring Test используются, например, для поддержки управляемых тестами транзакций или внедрения зависимостей в тестовые экземпляры.
TestExecutionListener
Примечание: некоторые части кода SeleniumTestExecutionListener пропущены для лучшей читаемости.
SeleniumTestExecutionListener предоставляет способ внедрить настроенный WebDriver в тестовые экземпляры. Экземпляр драйвера будет создан только один раз, а используемый драйвер можно просто изменить с @SeleniumTest аннотации @SeleniumTest . Самым важным было зарегистрировать драйвер в Bean Factory.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Overridepublic void prepareTestInstance(TestContext testContext) throws Exception { ApplicationContext context = testContext.getApplicationContext(); if (context instanceof ConfigurableApplicationContext) { SeleniumTest annotation = findAnnotation( testContext.getTestClass(), SeleniumTest.class); webDriver = BeanUtils.instantiate(annotation.driver()); // register the bean with bean factory }} |
Перед каждым методом тестирования базовый URL-адрес приложения будет открыт WebDriver :
|
1
2
3
4
5
6
7
|
@Overridepublic void beforeTestMethod(TestContext testContext) throws Exception { SeleniumTest annotation = findAnnotation( testContext.getTestClass(), SeleniumTest.class); webDriver.get(annotation.baseUrl());} |
Кроме того, при каждом сбое будет создаваться скриншот:
|
01
02
03
04
05
06
07
08
09
10
11
|
@Overridepublic void afterTestMethod(TestContext testContext) throws Exception { if (testContext.getTestException() == null) { return; } File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE); // do stuff with the screenshot} |
После каждого теста водитель будет закрыт:
|
1
2
3
4
5
6
|
@Overridepublic void afterTestClass(TestContext testContext) throws Exception { if (webDriver != null) { webDriver.quit(); }} |
Это всего лишь пример. Очень простая реализация. Мы могли бы расширить возможности аннотации и слушателя.
Тест
Выполнение теста ниже запустит браузер Chrome и выполнит несколько простых проверок с Selenium:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = Application.class)@WebIntegrationTest(value = "server.port=9000")public class HomeControllerTest { @Autowired private WebDriver driver; private HomePage homePage; @Before public void setUp() throws Exception { homePage = PageFactory.initElements(driver, HomePage.class); } @Test public void containsActuatorLinks() { homePage.assertThat() .hasActuatorLink("autoconfig", "beans", "configprops", "dump", "env", "health", "info", "metrics", "mappings", "trace") .hasNoActuatorLink("shutdown"); } @Test public void failingTest() { homePage.assertThat() .hasNoActuatorLink("autoconfig"); }} |
Тест использует простой объект страницы с пользовательскими утверждениями AssertJ. Вы можете найти полный исходный код в GitHub. Смотрите ссылки.
В случае сбоя скриншот, сделанный драйвером, будет сохранен в соответствующей директории.
Резюме
Интеграционное тестирование полностью загруженного приложения Spring Boot возможно в обычном тесте JUnit благодаря аннотациям @WebIntegrationTest и @SpringApplicationConfiguration . Запуск приложения в рамках теста открывает возможность нанять Selenium и запустить функциональные тесты с помощью браузера. Если вы объедините его с профилями и некоторыми другими функциями Spring Test (например, @Sql , @SqlConfig ), вы можете получить довольно мощное, но простое решение для интеграционных тестов.
использованная литература
- Исходный код: https://github.com/kolorobot/spring-boot-thymeleaf
- Весеннее тестирование загрузки: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing
- Весеннее тестирование: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html
| Ссылка: | Весеннее тестирование интеграции с Selenium от нашего партнера JCG Рафаля Боровца в блоге Codeleak.pl . |