단위 테스트를위한 ReflectionTestUtils

Mockito를 이용한 테스트 코드 작성시 발생한 이슈를 간단히 정리하고자 합니다.

 

@Table(name = "category")
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Category extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "parent_id")
    private Long parentId;

    @Builder
    public Category(String name, Long parentId) {
        this.name = name;
        this.parentId = parentId;
    }

}
  • 제가 보통 쓰는 엔티티 코드방식입니다.
  • 클래스 상단에 @Builder를 선언하면 IDENTITY전략을 설정한 기본키 값에 값을 할당할 수 있기에, 안전하지 않습니다.
  • 따라서, 생성자에 @Builder를 선언하여 엔티티 생성시 필요한 데이터만 받을 수 있도록 작성하였습니다.
  • 추가적으로 엔티티에는 @Setter 메소드를 선언하면 좋지 않습니다. 엔티티 혹은 객체는 불변한 성질을 가져야 하기 때문입니다. 만약 중간에 변경될 요지를 준다면 추후 코드추적하기가 어렵습니다.

 

@ExtendWith(MockitoExtension.class)
class CategoryServiceTest {

    @Mock
    private CategoryRepository categoryRepository;

    @Test
    @DisplayName("카테고리 조회")
    void categoryOneDepthSelect() {

        given(categoryRepository.findAll()).willReturn(getStubCatogories());
        CategoryService categoryService = new CategoryService(categoryRepository);

        CategoryDto categoryRoot = categoryService.categoryRoot();

        System.out.println(categoryRoot);

        assertThat(categoryRoot.getSubCategories().size()).isEqualTo(2);
        assertThat(categoryRoot.getSubCategories().get(0).getSubCategories().size()).isEqualTo(2);
        assertThat(categoryRoot.getSubCategories().get(1).getSubCategories().size()).isEqualTo(2);
    }

}
  • 목데이터로 테스트를 하기 위해 Mockito를 사용하였습니다.
  • 단위 테스트에 대한 자세한 내용은 아래 게시글을 참조 바랍니다

brunch.co.kr/@springboot/536

 

[임시 글..나중에 지울 예정] 단위 테스트 예습

스터디 중에.. 테스트 코드 작성이 너무 어렵다는 분들이 계셔서, 단위 테스트에 대해서 간략하게 먼저 소개합니다. 이 글은, 제가 이전에 작성했던 아래 글의 내용의 일부를 인용하였습니다. htt

brunch.co.kr

 

    private List<Category> getStubCatogories() {
        Category sub1 = new Category("SUB1", 0L);
        Category sub2 = new Category("SUB2", 0L);
        Category sub11 = new Category("SUB1-1", 1L);
        Category sub12 = new Category("SUB1-2", 1L);
        Category sub21 = new Category("SUB2-1", 2L);
        Category sub22 = new Category("SUB2-2", 2L);

        ReflectionTestUtils.setField(sub1, "id", 1L);
        ReflectionTestUtils.setField(sub2, "id", 2L);
        ReflectionTestUtils.setField(sub11, "id", 3L);
        ReflectionTestUtils.setField(sub12, "id", 4L);
        ReflectionTestUtils.setField(sub21, "id", 5L);
        ReflectionTestUtils.setField(sub22, "id", 6L);

        List<Category> categories = List.of(
            sub1, sub2, sub11, sub12, sub21, sub22
        );
        return categories;
    }
  • 카테고리 리스트에 대한 더미 데이터를 만들어야 했습니다.
  • 통합 테스트를 한다면, CategoryRepository의 findAll 메소드를 통해 DB에 존재하는 카테고리 데이터를 읽어와 사용할 수 있습니다.
  • 하지만, 단위테스트를 사용해야했기에 Category 엔티티를 직접 만들어야 했습니다.
  • Category 엔티티에서 Id 필드는 private 타입, setter 메소드 존재 X, 생성자 필드 X 하기 때문에 id 필드를 주입해야 했습니다.
  • ReflectionTestUtils를 이용하여 private 필드값에 직접 할당 할 수 있습니다.
    • spring-context 5.1.2 / spring-test 5.1.2 모듈이 필요합니다. 최신 스프링부트 버전을 사용하신다면 바로 사용하실 수 있습니다.

 

    @Test
    public void testRead1(){
        List<Category> stubCatogories = getStubCatogories();
        stubCatogories.forEach(category -> {
            System.out.println(category.getId());
        });
    }

  • 만든 더미데이터를 출력해보면 정상적으로 직접 세팅한 id값을 확인할 수 있습니다.

 

참고

www.baeldung.com/spring-reflection-test-utils