Вступление
Spring Framework - очень надежный фреймворк, выпущенный в 2002 году. Его основные функции могут применяться к простым Java-приложениям или расширяться до сложных современных веб-приложений.
Поскольку он постоянно обновляется и следует новым парадигмам архитектуры и программирования, он предлагает поддержку многих других фреймворков, которые работают с ним рука об руку.
С таким огромным набором функций вполне нормально, что он знакомит нас с некоторыми новыми аннотациями, которые являются ключевой частью разработки приложений Spring.
Конфигурация Spring полностью настраиваема, что изначально было сделано с помощью файлов конфигурации XML. Однако этот подход устарел, и в настоящее время большинство людей прибегают к настройке аннотаций.
При этом эта серия статей направлена на раскрытие возможностей, которые вы, как разработчик, должны настраивать и использовать фреймворк Spring:
- Аннотации Spring: @RequestMapping и его варианты
- Аннотации Spring: аннотации базовой платформы
- Аннотации Spring: Spring Cloud
- Аннотации Spring: аннотации к тестированию
Аннотации к весеннему тестированию
Разработка через тестирование (TDD) стала важной темой в наши дни, и считается крайне плохой практикой не тестировать ваши приложения должным образом.
Существует несколько широко используемых фреймворков, которые значительно упрощают эту работу для разработчиков, из которых JUnit является наиболее часто используемым.
Чтобы догнать современные практики программирования, Spring запустила
новую starter
зависимость, spring-boot-starter-test
, которая
состоит из нескольких фреймворков:
- JUnit
- Spring Test и Spring Boot Test
- AssertJ
- Hamcrest
- Mockito
- JSONassert
- JsonPath
В этой статье мы рассмотрим следующие тестовые аннотации:
- @BootstrapWith
- @ContextConfiguration
- @WebAppConfiguration
- @ContextHierarchy
- @ActiveProfiles
- @Rollback
- @Совершить
- @BeforeTransaction
- @AfterTransaction
- @Sql
- @SqlGroup
- @SqlConfig
- @SpringBootTest
- @DataJpaTest
- @DataMongoTest
- @WebMvcTest
- @MockBean
- @AutoConfigureMockMvc
- @JsonTest
- @TestPropertySource
- @Timed
- @Повторить
@BootstrapWith
@BootstrapWith
- это аннотация, которую вы, скорее всего, будете
использовать очень редко. Конфигурации по умолчанию для Spring
TestContext
Framework
более чем достаточно для большинства случаев использования.
Если это не так, вы можете изменить ContextLoader
или реализовать
собственный TestContext
среди множества других конфигураций, которые
вы можете изменить.
Опять же, это аннотация, которую вы, вероятно, не будете использовать, если вы не являетесь частью команды, которой действительно нужна настраиваемая конфигурация для Spring TestContext Framework.
@ContextConfiguration
@ContextConfiguration
- аннотация интеграционного теста, применяемая
на уровне класса для определения того, как Spring должен загружать
ApplicationContext
.
Эта аннотация может применяться вместе с @Component
(а также с
аннотациями, такими как @Service
, @Repository
и т. Д.)
@Configuration
а также с любым классом, содержащим @Bean
s.
Вы можете использовать аннотацию для ссылки либо на файлы XML, либо на классы Java:
@ContextConfiguration("/some-test-configuration-file.xml")
// @ContetConfiguration(locations = "/some-test-configuration-file.xml")
// You can use the optional `locations` flag as well.
public class ApplicationTests {
// Testing code...
}
@ContextConfiguration(classes = TestConfiguration.class)
public class ApplicationTests {
// Testing code...
}
Например, допустим, у нас есть TestBean
:
@Configuration
public class TestBean {
@Bean
public DeveloperService developerService() {
return new DeveloperService();
}
}
Если бы мы хотели сделать некоторые assert
для этого bean-компонента,
мы бы сделали что-то вроде:
@ContextConfiguration(classes = TestBean.class)
public class ApplicationTests {
@Autowired
private DeveloperService;
@Test
public void testBean() {
Developer dev = developerService.getDeveloperById(5);
assertEquals("David", dev.getName());
}
}
В настоящее время предпочтительнее полагаться на классовый подход,
поскольку XML обычно считается устаревшим подходом для регистрации
bean-компонентов. Если у вас более одного класса, вы, конечно, просто
укажите их через
classes = {TestBean.class, TestBean2.class, TestBean3.class}
и т. Д.
Это подводит нас к @Test
, о которой будет подробно рассказано ниже. А
пока давайте просто воспользуемся этим в иллюстративных целях.
@WebAppConfiguration
Если вы хотите, чтобы Spring WebApplicationContext
для ваших тестов
вместо обычного ApplicationContext
, вы можете использовать
@WebAppConfiguration
вместе с аннотацией @ContextConfiguration
@ContextConfiguration(classes = TestBean.class)
@WebAppConfiguration
public class ApplicationTests {
@Autowired
private DeveloperService;
// Rest of the code...
}
В качестве альтернативы вы можете указать value
или, скорее,
расположение WebApplicationContext
, если он не находится в каталоге
src/main/webapp
@WebAppConfiguration("some/other/location")
public class ApplicationTests {}
@ContextHierarchy
Еще одна аннотация, которая обычно используется редко (я лично не видел,
чтобы кто-нибудь использовал ее в проекте), - это аннотация
@ContextHierarchy
Это позволяет разработчику определять несколько @ContextConfiguration
на уровнях через отношения родитель-потомок .
Идея состоит в том, что дочерние контексты могут использовать bean-компоненты, зарегистрированные в родительских контекстах, и это улучшает возможность повторного использования bean-компонентов:
@ContextHierarchy({
@ContextConfiguration(classes = ApplicationTestConfiguration.class),
@ContextConfiguration(classes = WebApplicationTestConfiguration.class)
})
public class ApplicationTests {
}
Если вы хотите узнать больше об этой аннотации, документация содержит некоторую подробную информацию об иерархии контекста.
@ActiveProfiles
@ActiveProfiles
- это довольно простая и простая аннотация. Он
определяет, какой профиль должен быть активен при загрузке конфигурации
контекста:
@ContextConfiguration
@ActiveProfiles("dev")
public class ApplicationTests {}
Это означает, что должен быть активен профиль «dev».
Название аннотации подразумевает, что мы можем определить несколько профилей, которые мы можем:
@ContextConfiguration
@ActiveProfiles({"dev", "prod"})
public class ApplicationTests {}
Если вы хотите узнать больше о Spring Profiles , мы вам поможем!
@Rollback
Иногда, имея дело с базами данных, мы хотим отменить внесенные нами изменения, особенно если мы вызвали исключение.
@Rollback
определяет, должна ли транзакция метода, помеченного
@Transactional
быть отменена после завершения вызывающего ее метода
тестирования.
Его можно применять на уровне класса и метода:
- Уровень класса : определяет откат по умолчанию для всех методов тестирования в классе.
- Уровень метода : определяет откат для конкретного метода тестирования.
|
|
@Rollback(true)
@Test
public void someTest() {
// ...calling some transactional method
}
После завершения теста все изменения, внесенные транзакционным методом, будут отменены.
Интересно отметить тот факт, что вы можете установить для
необязательного флага значение false
, при котором Spring гарантирует,
что изменения не будут отменены. Установка для аннотации @Rollback
false
будет вести себя точно так же, как @Commit
.
@Совершить
В дополнение к предыдущему разделу @Commit
используется, когда мы
хотим гарантировать изменения в базе данных после запуска методов
тестирования.
Он ведет себя так же, как @Rollback(false)
и может применяться на
уровне класса или метода:
@Commit
@Test
public void someTest() {
// ...calling some transactional method
}
@BeforeTransaction
Иногда мы хотим запустить определенные фрагменты кода до совершения транзакций. Для этого нам, очевидно, нужно определить методы, специально написанные для этого.
Чтобы вызывать их перед каждой транзакцией, мы просто аннотируем их
аннотацией @BeforeTransaction
@BeforeTransaction
void methodBeforeTransaction() {
// ...ran before a transaction
}
Чтобы аннотация работала правильно, вам необходимо пометить свои
транзакционные методы с помощью @Transactional
.
Примечание . Начиная с Spring 4.3, эти методы не обязательно должны быть общедоступными.
@AfterTransaction
Имея ту же природу, что и аннотация @BeforeTransaction
@AfterTransaction
запускает определенный метод после совершения
транзакции:
@AfterTransaction
void methodAfterTransaction() {
// ...ran after a transaction
}
Примечание . Начиная с Spring 4.3, эти методы не обязательно должны быть общедоступными.
@Sql
Используя @Sql
и передавая имена схем, которые мы хотим выполнить, мы
можем программно (или декларативно) выполнять сценарии SQL.
По умолчанию эти сценарии @Before
перед любыми методами @Before.
Если мы определим сценарий, например createTable.sql
:
CREATE TABLE ITEM (ITEM_ID INT PRIMARY KEY, ITEM_NAME VARCHAR(256) NOT NULL);
Мы можем ссылаться на него и легко выполнять:
@Test
@Sql("/createTable.sql")
public void itemTest {
// ...some code that depends on the sql script above
}
@SqlGroup
@SqlGroup
позволяет нам объединять несколько сценариев SQL и запускать
их.
Если у нас есть другой сценарий, например, для dropTable.sql
той же
таблицы, dropTable.sql:
DROP TABLE ITEM;
Мы можем связать createTable.sql
со сценарием dropTable.sql
для
запуска до и после метода тестирования, например:
@Test
@SqlGroup({
@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = ""),
@Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD, scripts = ""),
})
public void itemTest {
// ...item table gets created, tested by the code and then dropped
}
@SqlConfig
Как следует из названия, следуя стандартным примерам аннотаций Spring,
аннотация @SqlConfig
используется для определения конфигурации
сценариев SQL - того, как они анализируются и выполняются.
Его можно применять на уровне класса или метода. Интеграционные тесты, которые требуют глобальной конфигурации для всех запущенных сценариев SQL, обычно используют подход на уровне классов, тогда как подход на уровне методов предназначен для локальных конфигураций определенных методов:
@Test
@Sql(scripts = "/createTable.sql",
config = @SqlConfig(attribute = "val", attribute2 = "val"))
public void itemTest {
// Some code...
}
В аннотацию @SqlConfig
можно передать 9 атрибутов:
blockCommentEndDelimiter
: Конечный разделитель для комментариев блокаblockCommentStartDelimiter
: начальный разделитель для комментариев блокаcommentPrefix
: префикс для однострочных комментариев.dataSource
: Имя bean-dataSource
encoding
: указание кодировки для скриптов.errorMode
: какой режим использовать при обнаружении ошибкиseparator
: символ, используемый для разделения операторов.transactionManager
: имя bean-компонента диспетчера транзакций.transactionMode
: какой режим использовать при выполнении сценариев SQL.
@SpringBootTest
@SpringBootTest
ищет тестовый класс, аннотированный с помощью
@SpringBootConfiguration
который в большинстве случаев является нашим
основным классом приложения, поскольку @SpringBootApplication
включает
в себя предыдущую аннотацию.
После обнаружения он создает контекст приложения для тестовой среды. Вы
даже можете запустить веб-среду, используя атрибут webEnvironment
@SpringBootTest
public class IntegrationTests {
// Rest of the code
}
@SpringBootTest(webEnvironment = pringBootTest.WebEnvironment.RANDOM_PORT)
public class WebEnvIntegrationTests {
// Rest of the code
}
@DataJpaTest
Используя @DataJpaTest
, мы можем тестировать приложения JPA. Он
применяется на уровне класса и создает контекст приложения для всех
@Enitity
вместе со встроенной базой данных, которая применяется по
умолчанию.
Примечание . Обычные @Component
не загружаются в контекст
приложения, созданный аннотацией @DataJpaTest
Он используется вместе с @RunWith(SpringRunner.class)
, которая
указывает, какие средства будут использовать отмеченный класс.
По умолчанию все транзакции JPA будут откатываться (вы можете изменить
это поведение, применив либо @Rollback(false)
либо @Commit
):
@RunWith(SpringRunner.class)
@DataJpaTest
public class SomeJpaTest {
// Rest of the code
}
Это классический тест JPA, однако, если вы хотите использовать реальную базу данных, вместо предоставленной встроенной базы данных в памяти, вы можете просто добавить еще одну аннотацию, чтобы предотвратить такое поведение:
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
public class SomeJpaTest {
// Rest of the code
}
@DataMongoTest
Очень похоже на @DataJpaTest
, для выполнения классических тестов
MongoDB мы применяем @DataMongoTest
вместе с аннотацией
@RunWith(SpringRunner.class)
.
Имейте в виду, что эта аннотация используется, когда тест применяется
только для тестирования компонентов MongoDB и добавляет только
@Document
в контекст приложения:
@RunWith(SpringRunner.class)
@DataMongoTest
public class SomeMongoTest {
// Rest of the code
}
Опять же, если вы хотите запустить это с реальной базой данных, а не со встроенной базой данных в памяти, предоставленной Mongo, вы можете исключить эту опцию:
@RunWith(SpringRunner.class)
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class SomeMongoTest {
// Rest of the code
}
@WebMvcTest
Опять же, очень похоже на @DataJpaTest
и @DataMongoTest
, для
выполнения классических тестов Spring MVC мы применяем @WebMvcTest
вместе с аннотацией @RunWith(SpringRunner.class)
.
Имейте в виду, что эффекты этой аннотации применимы только к инфраструктуре MVC. При этом он не создает экземпляр всего контекста.
Аннотацию можно использовать для тестирования одного контроллера,
передав его как атрибут, например @WebMvcTest(SomeController.class)
.
Чтобы создать экземпляры других необходимых зависимостей, таких как
службы, мы обычно используем аннотацию @MockBean
@WebMvcTest
настраивает MockMvc
который можно использовать для простого и быстрого
тестирования контроллеров MVC и создания экземпляров других участников:
@RunWith(SpringRunner.class)
@WebMvcTest(HomeController.class)
public class ControllerTests {
// Auto-configured to make mocking easier
@Autowired
private MockMvc mockMvc;
@MockBean
private SomeBean someBean;
@Test
public void someTest() {
// Test logic
}
}
@MockBean
При тестировании конкретных модулей, например, контроллера, мы хотим максимально изолировать их. Поскольку большинство компонентов Spring Application зависят от множества других компонентов (зависимостей), квинтэссенцией является обеспечение возможности индивидуального тестирования всех этих компонентов.
Для того, чтобы успешно изолировать объекты мы хотим проверить, в то же
время позволяя приложению работать нормально, мы издеваться или
имитировать зависимости. @MockBean
аннотаций используется , когда мы
хотим , чтобы дразнить зависимость в приложении:
@RunWith(SpringRunner.class)
@WebMvcTest(HomeController.class)
public class ControllerTests {
// Auto-configured to make mocking easier
@Autowired
private MockMvc mockMvc;
@MockBean
private SomeBean someBean;
@Test
public void someTest() {
// Test logic
}
}
В этом примере someBean
реальную зависимость. Если компонент
существует в контексте, макет заменяет его. Если его не существует,
макет добавляется в контекст как bean-компонент.
Примечание . Между аннотациями @Mock
и @MockBean
@Mock
взята
из библиотеки Mockito и эквивалентна вызову Mockito.mock()
. С другой
стороны, @MockBean
- это оболочка библиотеки Spring для аннотации
@Mock
@AutoConfigureMockMvc
Как следует из названия, @AutoConfigureMockMvc
при применении к
тестовому классу автоматически настраивает MockMvc
, точно так же, как
@WebMvcTest
автоматически настраивает его.
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTests {
@Autowired
private MockMvc mockMvc;
// Rest of the logic
}
Если вы хотите сосредоточиться только на веб-слое, рассмотрите
возможность использования аннотации @WebMvcTest
@JsonTest
Многие приложения имеют дело с сериализацией / десериализацией
JSON . Поэтому при тестировании
приложения имеет смысл убедиться, что он работает правильно. Используя
@JsonTest
, Spring автоматически настраивает поддерживаемый
преобразователь JSON (Jackson, Gson или Jsonb).
Обычно он используется вместе с @RunWith(SpringRunner.class)
и
используется для классических тестов JSON, сканирующих @JsonComponent
s.
@RunWith(SpringRunner.class)
@JsonTest
public class JsonTests {
@Test
public void someJsonTest() {
// Rest of the logic
}
}
@TestPropertySource
@TestPropertySource
применяется к уровню класса и определяет
расположение источников свойств, которые мы хотим использовать для
теста.
Эти свойства сохраняются как набор @PropertySource
в среде контекста
приложения. Эти свойства имеют приоритет над свойствами системы или
приложения.
По сути, когда мы хотим переопределить свойства системы / приложения конкретными свойствами для наших тестов, мы просто аннотируем тестовый класс:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
@TestPropertySource("classpath:applicationtest.properties")
public class ApplicationTest {
// Rest of the logic
}
С другой стороны, вы можете указать встроенные свойства вместо всего файла свойств:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
@TestPropertySource(properties = {"sa.website_name = stackabuse", "sa.website_url = www.stackabuse.com"})
public class ApplicationTest {
// Rest of the logic
}
@Timed
@Timed
определяет время в миллисекундах, в течение которого тестовый
метод должен завершить выполнение, иначе он завершится неудачно:
@Timed(millis = 1000)
public void testMethod() {
// Some test logic
}
Если на выполнение теста уходит больше секунды, он не сработает. Сюда
входят все повторы метода, если @Repeat
аннотация @Repeat.
@Повторить
@Repeat
определяет, сколько раз следует повторить тестовый метод:
@Repeat(5)
@Test
public void testMethod() {
// Some test logic
}
Этот тест будет повторен пять раз.
Заключение
Фреймворк Spring - это мощный и надежный фреймворк, который действительно изменил правила игры, когда дело доходит до разработки веб-приложений. Помимо всего прочего, он предлагает отличную поддержку TDD для приложений Spring и позволяет разработчикам легко и быстро настраивать любые виды тестов.