spring

junit5 repository 테스트 데이터 한 번만 setup(insert)하기

malangcow 2022. 9. 18.

다양한 필터링의 조회 검색 기능을 만들게 되었다.

그리고 테스트하기 위해서는 많은 insert문을 실행하는 setup 메소드를 만들게 되었는데 문제가 생겼다.

 

실제 dataSetup코드..

    public void dataSetup() {
        Member aMember = memberRepository.save(Member.builder().email("www.a.com").nickname("aaaa name").profileImage("image").build());
        Member bMember = memberRepository.save(Member.builder().email("www.b.com").nickname("bbbb name").profileImage("image").build());
        Member cMember = memberRepository.save(Member.builder().email("www.c.com").nickname("cccc name").profileImage("image").build());

        TechStack react = techStackRepository.save(TechStack.builder().name("react").build());
        TechStack angular = techStackRepository.save(TechStack.builder().name("angular").build());
        TechStack spring = techStackRepository.save(TechStack.builder().name("spring").build());
        TechStack nodejs = techStackRepository.save(TechStack.builder().name("nodejs").build());
        TechStack php = techStackRepository.save(TechStack.builder().name("php").build());

        Project aProject = projectRepository.save(Project.builder().member(aMember)
                .title("aaaa title").content("aaaa content").status(ProjectStatus.RECRUITING).build());
        Project bProject = projectRepository.save(Project.builder().member(bMember)
                .title("bbbb title").content("bbbb content").status(ProjectStatus.RECRUITING).build());
        Project cProject = projectRepository.save(Project.builder().member(cMember)
                .title("cccc title").content("cccc content").status(ProjectStatus.COMPLETED).build());
        Project dProject = projectRepository.save(Project.builder().member(aMember)
                .title("dddd title").content("dddd content").status(ProjectStatus.COMPLETED).build());


        projectTechStackRepository.save(new ProjectTechStack(aProject, react))
                .setProject(aProject);
        projectTechStackRepository.save(new ProjectTechStack(aProject, spring))
                .setProject(aProject);
        projectTechStackRepository.save(new ProjectTechStack(aProject, nodejs))
                .setProject(aProject);

        projectTechStackRepository.save(new ProjectTechStack(bProject, react))
                .setProject(bProject);
        projectTechStackRepository.save(new ProjectTechStack(bProject, spring))
                .setProject(bProject);
        projectTechStackRepository.save(new ProjectTechStack(bProject, nodejs))
                .setProject(bProject);

        projectTechStackRepository.save(new ProjectTechStack(cProject, php))
                .setProject(cProject);
        projectTechStackRepository.save(new ProjectTechStack(cProject, react))
                .setProject(cProject);

        projectTechStackRepository.save(new ProjectTechStack(dProject, php))
                .setProject(dProject);
        projectTechStackRepository.save(new ProjectTechStack(dProject, angular))
                .setProject(dProject);

        projectRepository.save(aProject);
        projectRepository.save(bProject);
        projectRepository.save(cProject);
        projectRepository.save(dProject);

        System.out.println("-------------------- insert query close ----------------\n\n");
    }
  • 시간이 상당히 걸린다..

 

어차피 전부 조회로직이라 사전에 삽입된 데이터의 변경로직이 없어

BeforeEach등을 사용하여 매번 테스트 함수마다 setup을 실행시키려면 매번 데이터도 지워줘야하고

무엇보다 시간이 너무 걸리고 굳이 그럴필요 있나라고 생각이 들었다.

 

@BeforeAll

  • junit5에서 제공해주는 어노테이션

테스트클래스가 시작할 때 한번만 동작하는 어노테이션을 찾았지만 이것은 함수가 static이여야만 동작한다.

그러면 setup함수에서 호출하는 repository도 전부 static에 테스트메소드들도 전부 static이 되어야해서 문제가 됐다.

 

@TestInstance

  • TestInstance.Lifecycle 설정이 가능. (default :PER_METHOD)
  • JUnit 5는 테스트 인스턴스 생성 기본 단위가 메소드라서
    테스트 클래스 속 각 테스트메소드 별로 따로 인스턴스가 생성되어 테스트가 실행 된다.
  • 테스트메소드 간 영향없이 독립적인 단위 테스트를 하기에 좋은데, 그럴필요가 없을 땐 사용자 임의로 변경해 줄수가 있었다.
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DataJpaTest
@ExtendWith(SpringExtension.class)
class QueryRepositoryTest {
    
    @Autowired
    private QueryRepository queryRepository;


	@BeforeAll
    public void dataSetup() {
    	queryRepository.save(..);
        queryRepository.save(..);
        queryRepository.save(..);
    	//...
	}
    
    
    @Test
    void 조회테스트1() {}
    
    @Test
    void 조회테스트2() {}
    
    @Test
    void 조회테스트3() {}

}

이런식으로 @TestInstance(TestInstance.Lifecycle.PER_CLASS)을 붙이면

testInstance lifecycle을 클래스 단위로 변경되고 @BeforeAll이 붙은 메소드가 static이 아니어도 경고가 안뜨고 올바르게 동작한다.

 

 

결과

처음에 setup시에만 시간이 많이 걸리고 나머지는 시간이 대폭 줄었다! 

테스트코드 초록표시는 언제봐도 짜릿하구나

 

 

 

reference : https://www.baeldung.com/java-beforeall-afterall-non-static

'spring' 카테고리의 다른 글

(Spring) Stomp로 채팅 동시접속자 구현해보기  (2) 2022.09.10

댓글