BookRepositoryTest - 책 목록보기

jihan kong·2022년 8월 24일
0

JUnit5

목록 보기
7/25
post-thumbnail

본 시리즈는 메타 코딩님의 Junit 강의를 학습한 내용을 바탕으로 정리하였습니다.

전 포스팅에서 책을 등록하는 로직을 구성하고 테스트해보았다. 이제 책의 목록을 보는 기능(select) 을 구현해보자.


책 목록 보기_test

BookRepositoryTest.java

    @Test
    public void 책목록보기_test() {
        // given
 
        // when
        List<Book> booksPS = bookRepository.findAll();
        
        // then
    	System.out.println(books.size());
    }

책 목록보기의 경우, 주어진 데이터로 실행을 하는 것이 아니라 findAll 메서드로 테스트를 진행한다.
따라서 // given 에는 아무것도 코딩하지 않아도 무방하다.
또한, assertEquals 를 통해 검증하는 것이 맞지만 일단은 booksPS에 titleauthor 값이 잘 들어갔는지 확인을 위해 books의 size를 출력해보도록 한다.

왼쪽의 초록색 세모버튼을 눌러 테스트를 진행하면...

given에서 삽입된 title과 author 값으로 size는 1이 나와야 하는데 0이 출력되었다. 즉, DB에 아무것도 들어가있지 않은 상태인 것이다. 왜 이런 현상이 발생한 걸까?


트랜잭션 실행 후, 초기화

전에 만들었던 책을 등록하는 테스트 코드를 다시 한번 살펴보자.

    // 1. 책 등록
    @Test
    public void 책등록_test() {
        // given (데이터 준비)
        String title = "junit5";
        String author = "메타코딩";
        Book book = Book.builder()
            .title(title)
            .author(author)
            .build();

        // when (테스트 실행)
        Book bookPS = bookRepository.save(book);

        // then (검증)
        assertEquals(title, bookPS.getTitle());
        assertEquals(author, bookPS.getAuthor());
    }

원래대로라면 위 테스트를 진행하고 bookRepository 에 값이 저장되어야 정상이다. 물론 위 테스트의 실행이 막 끝났을 때는 코드의 목적대로 잘 저장이 되었을 것이다.

그러나, 트랜잭션이 종료된 후에 Junit이 저장된 데이터를 초기화 시켰기 때문에 bookRepository 에 값이 남아있지 않는 것이다.

그렇기 때문에 "책 목록 보기" 테스트를 진행시키기 위해서는 책 등록 후, 트랜잭션이 종료가 되지 않게 하던지 종료가 되더라도 데이터를 영구적으로 가지고 있어서 다음 테스트에도 사용할 수 있게 해야한다.


그런데... 과연 그렇게 할 수 있을까?


테스트코드 작성을 위한 FIRST 원칙

클린코드로 유명한 로버트마틴이 제시했던 "올바른 테스트 코드 작성을 위한 FIRST 원칙" 의 내용은 다음과 같다.

F (Fast 빠르게)
테스트는 빠르게 수행되어야 한다.

I (Independent 독립적으로)
테스트는 독립적으로 수행되어야 한다.

R (Repeatable 반복가능하게)
테스트는 반복적으로 수행해도 결과가 같아야 한다.

S (Self-Validating 자가검증하는)
테스트는 자체적으로 검증이 가능해야 한다.

T (Timely 적시에)
테스트는 적시에 작성해야 한다.

이 중, "I (Independent)" 항목을 보자. 말 그대로 테스트는 독립적으로 수행되어야하고 A테스트의 결과가 B테스트의 결과에 영향을 미쳐서는 안된다는 내용이다.

상식적으로 생각해보아도 내가 구현한 기능이 올바르게 동작하는지를 검증하기 위해선 다른 메소드로부터 독립적이어야 순수한 테스트가 가능할 것이다.


독립적으로 구성한 테스트 코드

    // 2. 책 목록보기
    @Test
    public void 책목록보기_test() {
        // given
        String title = "junit5";
        String author = "메타코딩";
        Book book = Book.builder()
            .title(title)
            .author(author)
            .build();

        // when
        List<Book> booksPS = bookRepository.findAll();
        
        // then
        System.out.println(books.size());
    }

이렇게 테스트 코드를 작성하게 되면 메서드 안에서 자체적으로 값을 넣어주었기 때문에 외부의 값이 필요없이 순수하게 책목록보기_test 테스트를 실행할 수 있게 된다.

테스트 실행 시, 위와 같이 size가 1이 잘 출력되는 것을 볼 수 있다.
1이 나오는 것을 확인했으니 테스트 검증을 위해 then의 코드를 다음과 같이 수정하자.

		// then
        assertEquals(title, booksPS.get(0).getTitle());
        assertEquals(author, booksPS.get(0).getAuthor());

이제 테스트를 돌려보면...

오류없이 잘 통과가 되는 것을 볼 수 있다.
이제 책을 한 건만 조회하는 기능도 마저 구현해보자.

책 한 건 보기_test

BookRepositoryTest.java

    public void 책한건보기_test() {
        // given
        String title = "junit5";
        String author = "메타코딩";
        Book book = Book.builder()
            .title(title)
            .author(author)
            .build();

        // when
        Book bookPS = bookRepository.findById(1L).get();

        // then
        assertEquals(title, bookPS.getTitle());
        assertEquals(author, bookPS.getAuthor());
    }

책 목록 보기와 전체적인 구조는 비슷하다. 단지, Repository에서 조회할 때, findById 로 조회한다는 특징이 있다.



이렇게 select의 모든 내용들의 구현이 끝났다!!....만..

한 가지 아쉬운점이 있다. 각 테스트마다 // given 에 주어진 데이터의 내용을 일일히 써주는 것이 귀찮다...🤔

개선하고 싶은 부분

		String title = "junit5";
        String author = "메타코딩";
        Book book = Book.builder()
            .title(title)
            .author(author)
            .build();

이 내용을 메소드로 구현시켜 버리자. 감사하게도 Junit에는 우리가 원하는 기능을 수행해주는 어노테이션이 존재한다.


@BeforeEach

    @BeforeEach // 각 테스트 시작전에 한번씩 실행
    public void 데이터준비() {
        String title = "junit5";
        String author = "메타코딩";
        Book book = Book.builder()
            .title(title)
            .author(author)
            .build();
        bookRepository.save(book);
    } 
  • @BeforeEach : 이 어노테이션을 붙인 메서드는 테스트 메서드 실행 이전에 수행된다.

그렇기 때문에 책 등록, 책 목록, 책 한 건 테스트를 진행하기 전에 @BeforeEach 가 붙은 데이터준비 메소드가 먼저 실행된다.

이제 우리는 코드를 다음과 같이 개선할 수 있게 되었다.


BookRepositoryTest.java

	package site.metacoding.junitproject.domain;

	import static org.junit.jupiter.api.Assertions.assertEquals;

	import java.util.Optional;

	import org.junit.jupiter.api.BeforeEach;
	import org.junit.jupiter.api.Test;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

	@DataJpaTest    
	public class BookRepositoryTest {

    @Autowired 
    private BookRepository bookRepository;
    
    @BeforeEach // 각 테스트 시작전에 한번씩 실행
    public void 데이터준비() {
        String title = "junit5";
        String author = "메타코딩";
        Book book = Book.builder()
            .title(title)
            .author(author)
            .build();
        bookRepository.save(book);
    } 
    
    // 1. 책 등록
	// ...(생략)

    // 2. 책 목록보기
    @Test
    public void 책목록보기_test() {
        // given
        String title = "junit5";
        String author = "메타코딩";
        
        // ... (생략)
    
    // 3. 책 한건보기
    @Test
    public void 책한건보기_test() {
        // given
        String title = "junit5";
        String author = "메타코딩";
        
        // ... (생략)
profile
학습하며 도전하는 것을 즐기는 개발자

0개의 댓글