Есть несколько моментов, которые следует отметить при кэшировании, и это то, о чем я собираюсь здесь рассказать, это вряд ли будет всеобъемлющим, но основано на некоторых ситуациях, с которыми я столкнулся:
1. Кэширование основано на расположении файлов контекста приложения Spring.
Рассмотрим пример файла конфигурации Spring:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<?xml version='1.0' encoding='UTF-8' standalone='no'?> xsi:schemaLocation=' http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd'> <bean id='user1' class='org.bk.lmt.domain.TaskUser' p:username='user1' p:fullname='testUser1' /> <bean name='user2' class='org.bk.lmt.domain.TaskUser' p:username='user2' p:fullname='testUser' /> <bean class='org.bk.contextcaching.DelayBean'/> </beans> |
И пример теста для загрузки этого файла контекста и проверки чего-либо.
|
01
02
03
04
05
06
07
08
09
10
11
|
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = { 'contexttest.xml' })public class Test1 { @Autowired Map<String, TaskUser> usersMap; @Test public void testGetAUser() { TaskUser user = usersMap.get('user1'); assertThat(user.getFullname(), is('testUser1')); }} |
Я намеренно добавил компонент (DelayBean), для создания которого требуется около 2 секунд, чтобы имитировать контексты приложения Spring, которые медленно загружаются.
Если я сейчас запускаю небольшой набор тестов с двумя тестами, каждый из которых использует один и тот же контекст приложения, то поведение таково, что первый тест проходит около 2 секунд, но второй тест выполняется быстро из-за кэширования контекста.
Если бы был третий тест с использованием другого контекста приложения, этот тест снова потребовал бы времени для запуска, поскольку новый контекст приложения должен быть загружен:
|
1
2
3
4
5
|
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = { 'contexttest2.xml' })public class Test3 {...} |
2. Кэширование контекстов приложения учитывает активный профиль, в котором выполняется тест — по сути, профиль также является частью внутреннего ключа, который Spring использует для кэширования контекста, поэтому, если два теста используют один и тот же контекст приложения, но разные профили активным для каждого из тестов, тогда кэшированный контекст приложения не будет использоваться для второго теста:
|
01
02
03
04
05
06
07
08
09
10
|
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = { 'contexttest.xml' })@ActiveProfiles('dev1')public class Test1 {....@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = { 'contexttest.xml' })@ActiveProfiles('dev2')public class Test2 {.... |
3. Кэширование контекста приложения применяется даже при новом стиле @Configuration, который определяет контекст приложения и использует его в тестах:
|
1
2
3
4
5
6
7
8
|
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={TestConfiguration.class})public class Test1 {...@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={TestConfiguration.class})public class Test2 {.... |
Одним из следствий кэширования является то, что если тестовый класс изменяет состояние bean-компонента, тогда другой класс в наборе тестов, который использует контекст кэшированного приложения, в конечном итоге увидит модифицированный bean-компонент вместо bean-компонента, как он был определен в контексте приложения :
Например, рассмотрим два теста, каждый из которых изменяет бин в контексте, но утверждает состояние, как оно определено в контексте приложения. Здесь один из тестов может закончиться неудачей (в зависимости от порядка, в котором Junit выполняет тесты). ):
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={TestConfiguration.class})public class Test1 { @Autowired Map<String, TaskUser> usersMap; @Test public void testGetAUser1() { TaskUser user = usersMap.get('user1'); assertThat(user.getFullname(), is('testUser1')); user.setFullname('New Name'); } @Test public void testGetAUser2() { TaskUser user = usersMap.get('user1'); assertThat(user.getFullname(), is('testUser1')); user.setFullname('New Name'); }} |
Исправление состоит в том, чтобы указать поддержке тестов Spring, что контекст приложения теперь грязный и должен быть перезагружен для других тестов, и это делается с помощью аннотации @DirtiesContext, которая может указываться на уровне класса тестирования или уровня метода тестирования.
|
1
2
3
4
|
@Test@DirtiesContextpublic void testGetAUser2() {... |
Приятного кодирования и не забудьте поделиться!
Ссылка: поддержка весеннего тестирования и кеширование контекста от нашего партнера JCG Биджу Кунджуммена в блоге all and sundry.


