
Spring Boot와 JPA를 활용한 프로젝트에서 단위 테스트를 진행할 때,
ID 값이 필요한 로직을 테스트하는 문제에 직면했다.
예를 들어, 게시판(Board)을 생성하는 기능을 테스트할 때,
게시판을 작성한 작성자(Member)의 ID가 정상적으로 저장되는지 확인해야 한다.
하지만 JPA에서는 ID 값이 영속성 컨텍스트(Persistence Context)를 통해 자동 생성되므로, 단위 테스트에서 ID를 강제로 설정하는 방법을 찾아야 했다.
이번 글에서는 다양한 방법의 장단점을 분석하고, 최종적으로 Reflection을 활용하는 방식을 선택한 이유를 정리해보겠다.
@Entity
@Getter
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public Member(Long id) { // ID를 직접 입력받는 생성자 추가
this.id = id;
}
}
상속을 활용한 Proxy 객체 생성
public class MemberProxy extends Member {
public MemberProxy(Long id) {
super();
this.setId(id); // protected setter 필요
}
}
합성을 활용한 Proxy 객체 생성
public class MemberProxy {
private final Long id;
private final Member member;
public MemberProxy(Long id) {
this.id = id;
this.member = new Member();
}
public Long getId() {
return id;
}
}
class ParticipantTest {
private Member member;
@BeforeEach
void setUp() {
member = Mockito.spy(Fixture.member());
when(member.getId()).thenReturn(1L);
}
}
@BeforeEach
public void setUp() throws NoSuchFieldException, IllegalAccessException {
savedMember = Fixture.member(); // ID 없이 생성
// Reflection을 사용하여 ID 강제 설정
Field idField = Member.class.getDeclaredField("id");
idField.setAccessible(true);
idField.set(savedMember, 1L);
}
JPA 엔티티에서 ID 값이 필요한 단위 테스트를 진행하면서 여러 가지 방법을 시도했다.
Reflection을 사용하여 ID 값을 강제로 설정하는 방식이 가장 적합하다고 판단했다.
이 방법은 프로덕션 코드에는 전혀 영향을 주지 않으면서, 테스트에서 ID 값을 설정할 수 있는 장점이 있다.