Java 插入数据之前的Spring Boot@不可用
我正在用JUnit4和TestContainers编写一个简单的身份验证测试。我的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
@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<>());
}
}