Java 插入数据之前的Spring Boot@不可用

Java 插入数据之前的Spring Boot@不可用,java,spring-boot,spring-data-jpa,Java,Spring Boot,Spring Data Jpa,我正在用JUnit4和TestContainers编写一个简单的身份验证测试。我的@Before和@Before方法都是@Transactional,但当我在UserDetailsServiceImpl中查询数据时,它不存在,我无法找出原因。没有什么是异步的。任何想法 @Slf4j @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) @TestPropertySour

我正在用JUnit4和TestContainers编写一个简单的身份验证测试。我的
@Before
@Before
方法都是
@Transactional
,但当我在
UserDetailsServiceImpl
中查询数据时,它不存在,我无法找出原因。没有什么是异步的。任何想法

@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();
      }
  }

}
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=webEnvironment.DEFINED\u端口)
@TestPropertySource(locations=“classpath:application test.properties”)
公共抽象类DBEnabledTest{
@自动连线
受保护的实体管理器em;
@阶级规则
公共静态PostgreSQLContainer sqlContainer=新的PostgreSQLContainer(“postgres:11”)
.withDatabaseName(“测试场景”)
.withUsername(“postgres”)
.使用密码(“postgres”);
@课前
公共静态void setupEnv(){
setProperty(“spring.datasource.url”,sqlContainer.getJdbcUrl());
setProperty(“spring.datasource.username”,sqlContainer.getUsername());
setProperty(“spring.datasource.password”,sqlContainer.getPassword());
info(“使用-”+sqlContainer.getJdbcUrl()运行DB测试);
}
@之后
@交易的
公共无效截断b(){
List tables=em.createNativeQuery(“从信息_schema.tables中选择表_名称,其中表_schema='public'))。getResultList();
for(字符串表:表){
em.createNativeQuery(“截断表”+表+“级联”).executeUpdate();
}
}
}

@AutoConfigureMockMvc
公共类TestUserAuthentication扩展了DBEnabledTest{
@自动连线
私有TestRestTemplate;
@自动连线
私有用户存储库用户存储库;
@以前
@交易的
public void initDBForEachTestMethod(){
用户testUser=新用户();
testUser.setEmail(“test@user.com");
setPassword(新的BCryptPasswordEncoder().encode(“testUser1”));
testUser.setFirstName(“Jonh”);
testUser.setLastName(“面团”);
testUser.setRole(AppRole.USER);
userRepository.saveAndFlush(testUser);
}
@试验
@交易的
public void test_authenticationSuccess()引发异常{
反应性研究=
restTemplate.postForEntity(
“/api/user/login”,
JsonUtil.objectBuilder()
.put(“电子邮件”)test@user.com")
.put(“密码”、“testUser1”)
.toString(),
String.class
);
assertTrue(res.getStatusCode().is2xxSuccessful());
字符串体=res.getBody();
JsonNode node=JsonUtil.nodeFromString(body);
assertNotNull(node.get(“id”));
assertNotNull(node.get(“令牌”);
assertNotNull(node.get(“refreshToken”);
assertNotNull(node.get(“expiresAt”);
DecodedJWT DecodedJWT=JWTUtil.verifyToken(node.get(“token”).astex(),jwtConfig.getSecret());
资产质量(”test@user.com,decodedJWT.getSubject());
assertEquals(AppRole.USER,AppRole.valueOf(decodedJWT.getClaim(JWTUtil.ROLE_CLAIM.asString());
}
}

@组件
公共类UserDetailsServiceImpl实现UserDetailsService{
@自动连线
私有用户存储库用户存储库;
@凌驾
public UserDetails loadUserByUsername(字符串电子邮件)引发UsernameNotFoundException{
com.concentral.scenarios.domain.user.user applicationUser=userRepository.findByEmail(电子邮件);
//来自@Before的数据在此不可用!!!
if(applicationUser==null | | applicationUser.isDeleted()){
抛出新用户名NotFoundException(电子邮件);
}
if(applicationUser.getPassword()==null){
抛出新的非法访问错误();
}
返回新的org.springframework.security.core.userdetails.User(电子邮件,applicationUser.getPassword(),newarraylist());
}
}

这是因为在测试中,默认情况下会回滚事务

还描述了如果需要,如何使用
@Commit
注释进行更改:

默认情况下,框架为每个测试创建并回滚一个事务。[……]

如果希望提交事务(不常见,但在希望特定测试填充或修改数据库时偶尔有用),可以通过使用注释告诉TestContext框架使事务提交,而不是回滚

@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("test@user.com");
    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", "test@user.com")
                    .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("test@user.com", 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<>());
    }
}