При тестировании конечных точек REST с использованием Mock MVC Spring SecurityContextHolder иногда возвращает неправильное имя пользователя в рамках одного и того же теста. У меня есть служба, в которой есть метод, который возвращает имя пользователя, а репозиторий JPA проверяет, существует ли пользователь (перефразировано):
String username = SecurityContextHolder.getContext().getAuthentication().getName();
Optional<RemoteUser> foundUser = userRepository.findOneByUsername(username);
Тесты при необходимости помечаются @WithMockUser(username = "..." roles="...")
. После этого каждый тест прерывается, и контекст приложения Spring обновляется.
@RunWith(SpringRunner.class)
@SpringBootTest(classes = IntegrationTestApplication.class)
public abstract class IntegrationTest {
...
@Resource
private WebApplicationContext applicationContext;
protected MockMvc mockMvc;
...
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext).build();
}
...
}
Примерно 97-98% времени тесты проходят нормально. Однако иногда имя пользователя, возвращаемое объектом Authentication, не совпадает с тем, которое было определено в аннотации @WithMockUser
. Используя операторы журнала, я даже видел имена пользователей, используемые в других тестовых классах , которые уже выполняли . Перед каждым тестом настраиваются пользователи базы данных, поэтому, если возвращается имя пользователя, которого нет в базе данных, тест завершится неудачно в зависимости от случая, для которого пользователь нужен.
Еще более странно то, что этот метод в этом сервисе можно вызывать несколько раз в течение теста, и иногда имя пользователя правильное, а потом внезапно оказывается неверным. Я не понимаю, как такое возможно. Насколько я понимаю, bean-компонент SecurityContextHolder был потокобезопасным, и поэтому непостоянство тестов сбивает меня с толку. Как это может происходить?
Еще несколько замечаний:
- Использование Spring Boot 2.2.7
- Тесты не выполняются параллельно.
- Вышеупомянутая служба всегда лениво вводится через внедрение поля (
@Lazy
). Я не знаю, важна ли это деталь, но это не мой код, и это единственная служба, которая использует эту аннотацию, и почему это делается таким образом, мне неизвестно. - Есть несколько методов, помеченных
@Async
, и я подумал, что, возможно, могут быть побочные эффекты, но у меня нет ничего, чтобы поддержать это, и эта линия мышления - чистое плевание. - Я отлаживал TestSecurityContextHolder и видел, что методы которые очищают контекст, действительно вызываются.
- Я видел это SecurityContextHolder также дает неправильные данные о пользователе , но во-первых, нет ответа на вопрос, а во-вторых, нет одновременных запросы в моих тестовых примерах.