Spring Безопасность, JUnit: @WithUserДетали для пользователя, созданного в @Before

В тестах JUnit с помощью Spring MockMVC существует два метода аутентификации в качестве пользователя безопасности Spring: @WithMockUser создает фиктивного пользователя с предоставленными учетными данными, @WithUserDetails принимает имя пользователя и решает его правильную реализацию UserDetails с пользовательским UserDetailsService (UserDetailsServiceImpl).

В моем случае, UserDetailsService загружает пользователя из базы данных. Пользователь, которого я хочу использовать, был вставлен в метод @Before тестового набора.

Однако мой UserDetailsServiceImpl не находит пользователя.

В моем @Before я вставляю пользователя следующим образом:

User u = new User();
u.setEMail("[email protected]");
u = userRepository.save(u);

И в UserDetailsServiceImpl:

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = this.userRepository.findOneByEMail(username);

    if (user == null)
        throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username));
    return user;
}

Как я могу использовать учетную запись, созданную в @Before, с помощью @WithUserDetails?

Ответ 1

К сожалению, вы не можете сделать легко @WithUserDetails с @Before, потому что spring @WithUserDetails аннотации будут вызывать Spring безопасность контекста тестового слушателя перед запуском setUp метода с @Before.

Вот fooobar.com/questions/630749/... небольшая хитрость и ответ на ваш вопрос.

Ответ 2

@Inject
private EntityManager em;

@Inject
PlatformTransactionManager txManager;

@BeforeTransaction
public void setup() {
    new TransactionTemplate(txManager).execute(status -> {

        User u = new User();
        u.setEMail("[email protected]");
        em.save(u);

        return null;
    });
}

@AfterTransaction
public void cleanup() {
    new TransactionTemplate(txManager).execute(status -> {
        // Check if the entity is managed by EntityManager.
        // If not, make it managed with merge() and remove it.
        em.remove(em.contains(u) ? user1 : em.merge(u));
        return null;
    });
}


@Test
@Transactional
@WithUserDetails(value = "[email protected]", userDetailsServiceBeanName = "loadUserByUsername")
public void test() {

}

Ответ 3

Вы можете использовать @PostConstruct вместо @Before. Это помогло мне. Кто-нибудь может это подтвердить?