Reputation: 159
I'm writing a simple authentication test with JUnit4 and TestContainers. Both my @Before
and @After
methods are @Transactional
, but when I query for the data in UserDetailsServiceImpl
it is not present and I can not figure out why. There is nothing async. Any ideas.
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
@TestPropertySource(locations = "classpath:application-test.properties")
public abstract class DBEnabledTest {
@Autowired
protected EntityManager em;
@ClassRule
public static PostgreSQLContainer<?> sqlContainer = new PostgreSQLContainer<>("postgres:11")
.withDatabaseName("test_scenarios")
.withUsername("postgres")
.withPassword("postgres");
@BeforeClass
public static void setupEnv() {
System.setProperty("spring.datasource.url", sqlContainer.getJdbcUrl());
System.setProperty("spring.datasource.username", sqlContainer.getUsername());
System.setProperty("spring.datasource.password", sqlContainer.getPassword());
log.info("Running DB test with - " + sqlContainer.getJdbcUrl());
}
@After
@Transactional
public void truncateDb() {
List<String> tables = em.createNativeQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'").getResultList();
for (String table : tables) {
em.createNativeQuery("TRUNCATE TABLE " + table + " CASCADE").executeUpdate();
}
}
}
@AutoConfigureMockMvc
public class TestUserAuthentication extends DBEnabledTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserRepository userRepository;
@Before
@Transactional
public void initDBForEachTestMethod() {
User testUser = new User();
testUser.setEmail("[email protected]");
testUser.setPassword(new BCryptPasswordEncoder().encode("testUser1"));
testUser.setFirstName("Jonh");
testUser.setLastName("Dough");
testUser.setRole(AppRole.USER);
userRepository.saveAndFlush(testUser);
}
@Test
@Transactional
public void test_authenticationSuccess() throws Exception {
ResponseEntity<String> res =
restTemplate.postForEntity(
"/api/user/login",
JsonUtil.objectBuilder()
.put("email", "[email protected]")
.put("password", "testUser1")
.toString(),
String.class
);
assertTrue(res.getStatusCode().is2xxSuccessful());
String body = res.getBody();
JsonNode node = JsonUtil.nodeFromString(body);
assertNotNull(node.get("id"));
assertNotNull(node.get("token"));
assertNotNull(node.get("refreshToken"));
assertNotNull(node.get("expiresAt"));
DecodedJWT decodedJWT = JWTUtil.verifyToken(node.get("token").asText(), jwtConfig.getSecret());
assertEquals("[email protected]", decodedJWT.getSubject());
assertEquals(AppRole.USER, AppRole.valueOf(decodedJWT.getClaim(JWTUtil.ROLE_CLAIM).asString()));
}
}
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
com.concentric.scenarios.domain.user.User applicationUser = userRepository.findByEmail(email);
// data from @Before not available here !!!
if (applicationUser == null || applicationUser.isDeleted()) {
throw new UsernameNotFoundException(email);
}
if(applicationUser.getPassword() == null) {
throw new IllegalAccessError();
}
return new org.springframework.security.core.userdetails.User(email, applicationUser.getPassword(), new ArrayList<>());
}
}
Upvotes: 0
Views: 50
Reputation: 81930
That is because in the tests transactions get rolled back by default.
The section of the documentation describing this behaviour also describe how to change it if needed by using the @Commit
annotation:
By default, the framework creates and rolls back a transaction for each test. [...]
If you want a transaction to commit (unusual, but occasionally useful when you want a particular test to populate or modify the database), you can tell the TestContext framework to cause the transaction to commit instead of roll back by using the
@Commit
annotation.
Upvotes: 1