Spring Test Code 를 실컷 작성 하다가..
@Transactional Annotation 을 사용하여 SpringTestCode 를 작성했다.
실제 운영환경에서는 나타나지 않는 예외들이 많이 발생하였다.
SpringBoot Test Code 를 작성하며 프로젝트를 진행하는 것은 이번이 처음이라
아직 이해가 부족한 것 같다. @BeforeEach @AfterEach Annotation 을 사용하여
테스트 전후로 데이터 생성 및 삭제를 하여 테스트코드를 다시 작성 중이다.
다른 방법이 존재하는 지 확인해 봐야겠다.
public class ForgetPasswordEntity extends BaseEntity
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long pid;
@Column(nullable = false)
@Builder.Default
private boolean isComplete = false;
@Column(nullable = false)
private String tempPassword;
@Column(nullable = false)
private String previousPassword;
@ManyToOne
@JoinColumn(name = "auth_pid", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
@ToStringExclude
private AuthEntity auth;
@Entity(name = "auth")
@Getter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AuthEntity extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long pid;
....
@OneToMany(targetEntity = ForgetPasswordEntity.class, mappedBy = "auth", cascade = CascadeType.DETACH)
@ToStringExclude
@Builder.Default
private List<ForgetPasswordEntity> forgetPasswordList = new ArrayList<>();
public interface ForgetPasswordRepositoryCustom
{
Optional<ForgetPasswordEntity> findByAuthPid(Long authEntityPid);
}
@Repository
@RequiredArgsConstructor
@Log4j2
public class ForgetPasswordRepositoryCustomImpl implements ForgetPasswordRepositoryCustom
{
private final JPAQueryFactory jpaQueryFactory;
@Override
public Optional<ForgetPasswordEntity> findByAuthPid(Long authEntityPid)
{
QForgetPasswordEntity forgetPasswordEntity = QForgetPasswordEntity.forgetPasswordEntity;
return Optional.ofNullable(
jpaQueryFactory.selectFrom(forgetPasswordEntity)
.where(forgetPasswordEntity.auth.pid.eq(authEntityPid)).fetchOne());
}
}
정말 바보 같지만 여태 Repository 에 findByAuthEntity 라고 선언하여
Parameter 로 AuthEntity를 사용했다.
결과는 무한 참조로 인해 해당 Querydsl 쿼리를 사용하지 못 했고 authEntity 에서 forgetPasswordList 를 그래프 탐색하여 forEach 를 돌려가며 찾는 비효율적인 짓을 했다.
그것마저 lazyinitializationexception 가 빈번하게 일어났다. ㅎㅎ
요즘 너무 멍청한 짓을 하는 것 같다.. 화이팅
SpringBoot 테스트 코드 작성 중 다음과 같은 에러가 발생했다
java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: DRBG, provider: SUN, class: sun.security.provider.DRBG)
... 아름답다
특정 알고리즘을 지원하지 않을 때 발생하는 예외
DRBG 알고리즘의 구현체를 찾지 못해서 발생하는 예외이다.
운영환경에서는 잘만돌아가는데 테스트환경에서만 삐지는 나쁜 친구다.
테스트 하는 환경이 새로운 비밀번호를 Random 하게 생성하는데 조건이 맞을때 까지 재귀한다.
아마 거기서 삔또가 상한것 같다.. 테스트니 일단 임의로 바꾸고 정규식에 맞는 비밀번호를 생성하는
효율적인 방법에 대해서 생각해 보아야 겠다.
@Test
void changePassword_SUCCESS()
{
AuthDTO.NewPassword.Request generateNewPassword = AuthDTO.NewPassword.Request.builder().loginId("test00@naver.com").build();
forgetPasswordService.assginNewPassword(generateNewPassword);
String newPasswordForTempLogin = forgetPasswordService.generateTempPassword();
String accessToken = tokenProvider.generateAccessToken("test00@naver.com", MEMBER_ROLE.STUDENT.name(), AuthProvider.DEFAULT.name());
private final String regexLevel1 = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[~!@#$%^&*()+|=])[A-Za-z\\d~!@#$%^&*()+|=]{10,30}$";
// 비밀번호는 연속적으로 사용 불가능
private final String regexLevel2 = "(\\w)\\1\\1\\1";
private final MemberRepository memberRepository ;
private final ForgetPasswordRepository forgetPasswordRepository ;
private final PasswordEncoder passwordEncoder ;
private final AuthRepository authRepository ;
private final TokenProvider tokenProvider ;
@Override
public String generateTempPassword()
{
SecureRandom random = new SecureRandom();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 20; i++) {
int randomIndex = random.nextInt(regexLevel1.length());
char randomChar = regexLevel1.charAt(randomIndex);
builder.append(randomChar);
}
String generatedPassword = builder.toString();
if (!generatedPassword.matches(regexLevel1) && !generatedPassword.matches(regexLevel2)) {
// 일치하지 않으면 재귀적으로 다시 생성
return generateTempPassword();
}
return generatedPassword;
}