스프링 입문 - Ch 3. 회원 관리 예제 - 백엔드 개발(2)

seren-dev·2022년 3월 22일
0

스프링 입문

목록 보기
4/11

회원 리포지토리 테스트 케이스 작성

테스트케이스 작성: 회원 리포지토리 클래스가 정상적으로 동작하는가 검증하는 방법

개발한 기능을 실행해서 테스트 할 때
자바의 main 메서드를 통해서 실행하거나, 웹 애플리케이션의 컨트롤러를 통해서 해당 기능을 실행한다.
이러한 방법은 준비하고 실행하는데 오래 걸리고, 반복 실행하기 어렵고 여러 테스트를 한번에 실행하기 어렵다는 단점이 있다.
자바는 JUnit이라는 프레임워크로 테스트 코드를 만들고 코드를 실행해서 이러한 문제를 해결한다.


test/java/hello.hellospring 패키지 내에 repository 패키지를 만들고 그 패키지 내에 MemoryMemberRepositoryTest 클래스를 만든다.

다른 데서 사용하지 않기 때문에 굳이 public이 아니어도 됨.

save()

	@Test
    public void save() {
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        Member result = repository.findById(member.getId()).get();
        //findById() 반환 타입이 optional이기 때문에 optional에서 값을 꺼내기 위해 get() 사용
        
        //System.out.println("result = " + (result == member));
        //Assertions.assertEquals(member, result);
        assertThat(result).isEqualTo(member);
    }
  1. System.out.println("result = " + (result == member));
    결과: result = true

  2. Assertions.assertEquals(member, result); // expected, actual
    (junit.jupiter.api)
    성공: 아무것도 안 뜨지만 초록색 체크
    실패:

org.opentest4j.AssertionFailedError: 
Expected :hello.hellospring.domain.Member@5c671d7f
Actual   :null
  1. Assertions.assertThat(result).isEqualTo(member);
    assertThat(result).isEqualTo(member); //actual, expected
    (assertj.core.api)
  • alt+enter하면 Assertions를 static import 가능

실무에서는 이걸 빌드 툴과 엮어서 빌드 툴에서 빌드할 때 테스트 케이스를 통과하지 못하면 다음 단계로 못 넘어가게 막음


findByName(), findAll()

    @Test
    public void findByName() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        assertThat(result).isEqualTo(member1);

    }

    @Test
    public void findAll() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }

테스트 케이스의 장점은
class 레벨(MemoryMemberRepositoryTest)에서 돌리거나 hello.hellospring 패키지에서 돌리면 전체 클래스 돌리는 것 가능

assertThat(result.size()).isEqualTo(3);이면 실패

org.opentest4j.AssertionFailedError: 
expected: 3
 but was: 2
Expected :3
Actual   :2

MemoryMemberRepository의 멤버를 static으로하고 모든 메소드를 테스트하면 다음과 같은 오류가 뜸

  • findAll 메소드까지 구현하고 난 후 전체 클래스에서 test하면 오류가 뜸
  • 테스트 순서가 보장이 안됨
  • findAll -> findByName -> save 순서인 경우, findAll에서 spring1, spring2가 이미 저장이 된 상태이기 때문에 findByName에서 fail이 뜸

테스트 하나가 끝나고나면 데이터를 클리어 해줘야 함

MemoryMemberRepository 클래스에서 clearStore 메소드 작성

public void clearStore() {
        store.clear();
    }

그리고 test의 afterEach메소드에서 함수 작성
@AfterEach : 각 테스트가 종료될 때 마다 이 기능을 실행한다.

    @AfterEach
    public void afterEach() {
        repository.clearStore();
    }

test는 서로 순서와 의존관계 없이 설계되어야 하기 때문에 하나의 테스트가 끝날 때마다 저장소나 공용 데이터를 깔끔하게 지워줘야한다.
또는 외부 리소스를 초기화할 때 도움이 된다. 예를 들어서 테스트의 결과로 특정 파일을 만들었다면, 해당 파일을 지우는 일을 하면 된다.

TDD 테스트 주도 개발

  • 개발(구현 클래스 만들기) -> 테스트가 아니라
  • 테스트 코드를 먼저 만들고 개발(구현 클래스를 만들어 돌려봄)하는 것

MemberRepository repository = new MemoryMemberRepository();
repository를 인터페이스로 설계 할 경우, MemberRepository 인터페이스를 구현한 구현체의 변경이 용이해진다.
하지만 repository.clearStore() 함수를 사용해야 하기 때문에 MemoryMemberRepository로 선언한다.

JUnit 테스트는 각각의 테스트마다 해당 멤버 필드를 모두 새로 생성합니다.

전체 코드

MemoryMemberRepositoryTest.java

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.*;

class MemoryMemberRepositoryTest {

    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach
    public void afterEach() {
        repository.clearStore();
    }

    @Test
    public void save() {
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        Member result = repository.findById(member.getId()).get();
        //findById() 반환 타입이 optional이기 때문에 optional에서 값을 꺼내기 위해 get() 사용

        //System.out.println("result = " + (result == member));
        //Assertions.assertEquals(member, result);
        assertThat(result).isEqualTo(member);
    }

    @Test
    public void findByName() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        assertThat(result).isEqualTo(member1);

    }

    @Test
    public void findAll() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        List<Member> result = repository.findAll();

        assertThat(result.size()).isEqualTo(2);
    }
}

0개의 댓글