Spring 심화주차 개인 과제 진행 중 어려웠던 부분

김현찬·2025년 6월 11일

1.@EntityGraph

Lv.2 과제 진행 사항에 fetch join을 사용하여 N+1 문제를 해결하고 있는 TodoRepository를 동일하게 동작하는 @EntityGraph기반의 구현으로 수정하는 부분이 있었습니다.

우선 @EntityGraph가 무엇인지 간단하게 알아보았습니다.

간단하게 말해 fetch join을 어노테이션으로 사용할 수 있도록 만들어 준 기능이라는 사실을 알았습니다.

여기서 의문이 생겼습니다.

그냥 쿼리문 안에 JOIN FETCH 쓰면 굳이 어노테이션 추가 안해도 되는 거 아닌가? 왜 @EntityGraph를 사용하지?

하여 둘의 차이점을 알아보았습니다.

@EntityGraph를 사용하는 이유 및 상황 내용 정리 블로그

    @Query("SELECT t FROM Todo t LEFT JOIN FETCH t.user u ORDER BY t.modifiedAt DESC")
    Page<Todo> findAllByOrderByModifiedAtDesc(Pageable pageable);

위 코드를

    @Query("SELECT t FROM Todo t ORDER BY t.modifiedAt DESC")
    @EntityGraph(attributePaths = {"user"})
    Page<Todo> findAllByOrderByModifiedAtDesc(Pageable pageable);

이와 같이 수정하여 해결했습니다.

2. AssertionFailedError

Lv.3-1의 테스트코드 수정 과정에서 AssertionFailedError에러가 발생했습니다.

검색을 통해 테스트를 수행할 때 기대한 값과 실제 값이 일치하지 않을 경우 발생하는 에러라는 것을 알았습니다.

@ExtendWith(SpringExtension.class)
class PasswordEncoderTest {

    @InjectMocks
    private PasswordEncoder passwordEncoder;

    @Test
    void matches_메서드가_정상적으로_동작한다() {
        // given
        String rawPassword = "testPassword";
        String encodedPassword = passwordEncoder.encode(rawPassword);

        // when
        boolean matches = passwordEncoder.matches(encodedPassword, rawPassword);

        // then
        assertTrue(matches);
    }
}

위 코드는 저장된 비밀번호와 입력한 비밀번호를 비교하는 테스트 로직입니다.

처음 테스트 코드를 살펴보았을 때 크게 문제가 될만한 부분을 찾지 못했습니다.
하여 테스트 로직을 처음부터 다시 짚어보았습니다.

given부분 (테스트 데이터 준비 부분)에서
rawPasswordtestPassword이고,
encodedPasswordpasswordEncoder의 기능인 encoderrawPassword를 인코딩한 값을 담고있습니다.

when부분 (실제 테스틀 로직)에서
boolean타입의 변수 matchespasswordEncoder의 기능인 matches를 이용하여 encodedPasswordtestPassword가 같다면 true, 다르면 false가 반환되도록 합니다.

then부분 (테스트 검증 로직)에서
assertTruematches의 값이 true인지 확인합니다.

위 흐름에서 인코딩한 데이터의 값도 testPassword이고, 비교 대상 값도 testPassword인데, 테스트는 실패하는 상황이었습니다.

따라서 비밀번호 인코딩 과정에서 문제가 발생했을 수 있겠다는 생각으로, PasswordEncoder클래스를 확인했습니다.

(PasswordEncoder클래스입니다.)

@Component
public class PasswordEncoder {

    public String encode(String rawPassword) {
        return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray());
    }

    public boolean matches(String rawPassword, String encodedPassword) {
        BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword);
        return result.verified;
    }
}

PasswordEncoder클래스를 확인해보니 사용중인 matches메서드의 매개변수는 (rawPassword, encodedPassword)의 구조인 반면, 테스트 코드는 (encodedPassword, rawPassword)로 사용중인 사실을 확인했습니다.

따라서 테스트 코드의 when부분을 다음과 같이 수정하였습니다.

        // when
        boolean matches = passwordEncoder.matches(rawPassword, encodedPassword);

이 후 테스트해보니 정상적으로 테스트가 완료되었습니다.

0개의 댓글