spring

ReflectionTestUtils로 더미데이터 DB에 넣기

가을맛 2023. 10. 25. 22:53

원티드 프리온보딩 백엔드 인턴십 10월 (7기) - 첫번째 프로젝트로 소셜 미디어 통합 Feed 서비스 API를 개발하는 과제를 받았다.

나는 게시물 좋아요 API, 게시물 공유 API 구현을 담당하게 되었는데, 동작을 확인하려면 DB에 데이터를 넣어야할 것 같았다. 그런데 요구사항 명세에는 데이터 저장에 대한 부분이 없어서 저장 기능을 굳이 구현하기는 좀 (다른 테이블과 연관관계가 있어서 복잡함)... 그래서 일단 더미데이터를 넣어보기로 했다.

기능 개발을 위해 구현된 Post 엔티티 기본 생성자 하나 뿐인데 Protect로 막혀있어서 어떤 생성자도 사용할 수 없는 상황이다. 마침 어제 공부했던 ReflectionTestUtils가 생각나서, 이걸로 테스트용 더미 데이터를 넣어보기로 했다.

 

ReflectionTestUtils

  • 리플렉션 기반 유틸리티 메서드의 모음
  • 원래라면 접근 제한되었을 변수/메서드에 접근하고 수정/호출 할 수 있게 해준다.
  • ORM 프레임워크 (Jpa,Hibernate 등) Domain Entity 의 private method를 통합/단위테스트 할 때 사용할 수 있다.
package com.skeleton.feed;

import com.skeleton.feed.entity.Post;
import com.skeleton.feed.enums.SnsType;
import com.skeleton.feed.repository.PostRepository;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.RepeatedTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.util.ReflectionTestUtils;

import java.io.BufferedReader;
import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.util.Random;
import java.util.UUID;

@SpringBootTest
class DummyPostDataInit {

    static SnsType[] snsTypes;
    static Random random;
    static BufferedReader br;
    static String s = "국회나 그 위원회의\n" +
            "대한민국은 국제평화의 유지에 노력하고 침략적 전쟁을 부인한다.\n" +
            "중앙선거관리위원회는\n" +
            "대법원장과 대법관이 아닌 법관의 임기는 10년으로 하며, 법률이 정하는 바에 의하여 연임할 수 있다.\n" +
            "대통령의 국법상 행위\n" +
            "국회는 국무총리 또는 국무위원의 해임을 대통령에게 건의할 수 있다.\n" +
            "언론·출판은 타인의\n" +
            "나는 헌법을 준수하고 국가를 보위하며 조국의 평화적 통일과 국민의 자유와 복리의 증진 및 민족문화의 창달에 노력하여 대통령으로서의 직책을 성실히 수행할 것을 국민 앞에 엄숙히 선서합니다.\n" +
            "국무총리 또는 행정각\n" +
            "국정감사 및 조사에 관한 절차 기타 필요한 사항은 법률로 정한다.\n" +
            "형사피의자 또는 형사\n" +
            "광물 기타 중요한 지하자원·수산자원·수력과 경제상 이용할 수 있는 자연력은 법률이 정하는 바에 의하여 일정한 기간 그 채취·개발 또는 이용을 특허할 수 있다.\n" +
            "비상계엄이 선포된 때\n" +
            "국회에 제출된 법률안 기타의 의안은 회기중에 의결되지 못한 이유로 폐기되지 아니한다. 다만, 국회의원의 임기가 만료된 때에는 그러하지 아니하다.\n" +
            "언론·출판에 대한 허\n" +
            "정부는 예산에 변경을 가할 필요가 있을 때에는 추가경정예산안을 편성하여 국회에 제출할 수 있다.\n" +
            "대통령의 임기는 5년\n" +
            "농업생산성의 제고와 농지의 합리적인 이용을 위하거나 불가피한 사정으로 발생하는 농지의 임대차와 위탁경영은 법률이 정하는 바에 의하여 인정된다.\n" +
            "모든 국민은 통신의\n" +
            "모든 국민은 신체의 자유를 가진다. 누구든지 법률에 의하지 아니하고는 체포·구속·압수·수색 또는 심문을 받지 아니하며, 법률과 적법한 절차에 의하지 아니하고는 처벌·보안처분 또는 강제노역을 받지 아니한다.";
    @Autowired
    private PostRepository postRepository;

    @BeforeAll
    static void init() throws Exception {
        snsTypes = SnsType.values();
        random = new Random();
        br = new BufferedReader(new StringReader(s));

    }

    @RepeatedTest(10)
    void addDummyData() throws Exception {

        // 생성자 public으로 변경
        Constructor<?>[] constructor = Post.class.getDeclaredConstructors();
        constructor[0].setAccessible(true); // 접근제어자 강제 변경
        Post post = (Post) constructor[0].newInstance();

        //필드값 주입
        ReflectionTestUtils.setField(post, "contentId", UUID.randomUUID().toString());
        ReflectionTestUtils.setField(post, "title", br.readLine());
        ReflectionTestUtils.setField(post, "content", br.readLine());
        ReflectionTestUtils.setField(post, "type", snsTypes[random.nextInt(snsTypes.length)]); // SnsType 랜덤

        //DB 저장
        postRepository.save(post);

    }

}

한글 Lorem Ipsum

테스트 데이터가 다 똑같거나 영어면 구분이 힘들어서 한글 Lorem Ipsum 로 더미데이터를 만들었다. 그냥 대충 해도 되긴하지만 식별이 쉬우면 아무래도 기분이 좋다.


어제 공부하면서도 쓸만하겠는데? 했던거지만 이렇게 바로 써먹게 될 줄은 몰랐는데.. 좀 더 응용하면 연관관계인 다른 엔티티에도 작업할 수 있을 것 같다. 하지만 귀찮으니 생략. 필요하면 구현해 봐야겠다.