randomname
randomname

Reputation: 159

Spring Boot @Before inserted data not available

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

Answers (1)

Jens Schauder
Jens Schauder

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

Related Questions