2023 12 13 오늘 새벽의 삽질

XingXi·2023년 12월 13일
0

기록

목록 보기
5/33

2023 12 13

Spring Test Code 를 실컷 작성 하다가..

🍕@Transactionl -> X

@Transactional Annotation 을 사용하여 SpringTestCode 를 작성했다.
실제 운영환경에서는 나타나지 않는 예외들이 많이 발생하였다.
SpringBoot Test Code 를 작성하며 프로젝트를 진행하는 것은 이번이 처음이라
아직 이해가 부족한 것 같다. @BeforeEach @AfterEach Annotation 을 사용하여
테스트 전후로 데이터 생성 및 삭제를 하여 테스트코드를 다시 작성 중이다.
다른 방법이 존재하는 지 확인해 봐야겠다.

🍕AuthEntity 대신 AuthEntityPid

ForgetPasswordEntity.java

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;
    

AuthEntity.java

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

ForgetPasswordRepositoryCustom.java


public interface ForgetPasswordRepositoryCustom 
{
    Optional<ForgetPasswordEntity> findByAuthPid(Long authEntityPid);
}
    

ForgetPasswordRepositoryCustom.java


@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 가 빈번하게 일어났다. ㅎㅎ
요즘 너무 멍청한 짓을 하는 것 같다.. 화이팅

🍕 java.security.NoSuchAlgorithmException

SpringBoot 테스트 코드 작성 중 다음과 같은 에러가 발생했다

java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: DRBG, provider: SUN, class: sun.security.provider.DRBG)
... 아름답다

java.security.NoSuchAlgorithmException

특정 알고리즘을 지원하지 않을 때 발생하는 예외

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

ForgetPasswordImpl.java ( 문제의 난수 생성 메소드 )

    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;
    }

0개의 댓글