TIL_220712_테스트 코드

창고·2022년 7월 12일
0

1. 테스트를 잘 하기 위한 기반

  • 클래스나 메소드가 SRP를 잘 지키고, 크기가 적절히 작아야 함
  • 적절한 Mocking을 통한 격리성 확보
  • 당연히 잘 돌겠지라는 생각말고 꼼꼼히 테스트 && 너무 과도하게 많은 테스트와 코드량이 생기지 않도록 적절히 끊기
  • 테스트 코드 개선을 위한 노력 (refactoring, 기법에 대한 고민 등)

2. JUnit5 / Mockit 활용 테스트

  • ctrl + shift + t : 테스트를 위한 클래스 생성

    테스트 오류 발생해서 아래 링크 참고하였음
    https://velog.io/@be_have98/IntelliJ-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%8B%A4%ED%96%89-%EC%8B%9C-Execution-failed-for-task-test.-%EC%98%A4%EB%A5%98

  • 테스트 관련 Annotation

    • @SpringBootTest : JUnit 테스트를 위한 Annotation
    • @ExtendWith(MockitoExtension.class) : Mockito를 활용한 테스트를 위한 Annotation
      • @Mock : 가상의 Mock을 지정
      • @InjectMocks : Mock을 주입
    • @Test : 테스트를 위한 메소드에 붙이는 Annotation
    • 추후에 좀 더 레퍼런스 찾아볼 것
  • 테스트용 객체, requestrefactoring 하여 private final 변수로 지정

  • 테스트 구조

    • given : 테스트에 활용될 mock, local variable, captor 등을 설정
      • given 메소드 호출
      • captor : mock 객체가 parameter로 받은 값을 캡쳐함
        ArgumentCaptor<T> variable = ArgumentCaptor.forClass(T.class)
    • when : 테스트하고자 하는 동작과 이로 인해 생기는 결과값 등을 설정
    • then : verify, assertion 등으로 우리가 예상하는 동작/결과와 비교
      • verify(~~, times(n)).save(captor.capture()); : ~~에 1번 저장될 때마다 캡처
      • captor.getValue(); : 캡처한 값을 가져옴
      • assertEquals(예상값, 1~2로 나타난 실제 결과값) : 예상값과 실제 결과값 비교
  • servicecreatedIdol 테스트

// @SpringBootTest // JUnit 테스트를 위한 annotation
// (실제 실행하는 것처럼 모든 bean을 생성하여 테스트)
@ExtendWith(MockitoExtension.class) // Mockito를 활용하여 테스트
class IMakerServiceTest {
    @Mock // 가상의 mock를 지정
    private IdolRepository idolRepository;

    @Mock // 가상의 mock를 지정
    private GraduatedIdolRepository graduatedIdolRepository;

    // @Autowired
    @InjectMocks // @Mock을 주입
    private IMakerService iMakerService;

    // 테스트용 객체를 refactoring
    private final Idol defaultIdol = Idol.builder()
            .idolLevel(NORMAL)
            .idolType(COOL)
            .experienceYears(1)
            .statusCode(StatusCode.ACTIVATED)
            .name("name")
            .age(16)
            .build();

    // 테스트용 request를 refactoring
    private final CreateIdol.Request defaultCreateRequest = CreateIdol.Request.builder()
            .idolLevel(NORMAL)
            .idolType(COOL)
            .experienceYears(1)
            .memberId("memberId")
            .name("name")
            .age(16)
            .build();

    @Test
    void createIdolTest_success() {
        //1. given : 테스트에 활용될 mock, 지역변수 등

        given(idolRepository.findByMemberId(anyString()))
                .willReturn(Optional.empty());

        // Mock 객체가 동작 중에 parameter로 받은 값을 캡쳐하기 위해 생성
        ArgumentCaptor<Idol> captor =
                ArgumentCaptor.forClass(Idol.class);
        // idol 타입을 저장하는 captor 생성성

       //2. when : 테스트하고자 하는 동작, 이로 인해 생기는 결과값
        CreateIdol.Response idol = iMakerService.createIdol(defaultCreateRequest);

        //3. then : assertion 등으로 우리가 예상하는 동작/결과를 출력을 하는지
        verify(idolRepository, times(1)) // idolRepository에 1번 저장될 때마다
                .save(captor.capture());
        Idol savedIdol = captor.getValue();
        assertEquals(NORMAL, savedIdol.getIdolLevel());
        assertEquals(COOL, savedIdol.getIdolType());
        assertEquals(1, savedIdol.getExperienceYears());
        assertEquals(16, savedIdol.getAge());
    }

    @Test
    void createIdolTest_failed_with_duplicated() {
        //1. given : 테스트에 활용될 mock, 지역변수 등

        given(idolRepository.findByMemberId(anyString()))
                .willReturn(Optional.of(defaultIdol));

        // Mock 객체가 동작 중에 parameter로 받은 값을 캡쳐하기 위해 생성
        ArgumentCaptor<Idol> captor =
                ArgumentCaptor.forClass(Idol.class);
        // idol 타입을 저장하는 captor 생성

        // 2. when : 테스트하고자 하는 동작, 이로 인해 생기는 결과값
        // → 어차피 실패할 것이라 response 값을 못 받음

        //3. then : assertion 등으로 우리가 예상하는 동작/결과를 출력을 하는지
        IMakerException iMakerException = assertThrows(IMakerException.class,
                () -> iMakerService.createIdol(defaultCreateRequest)
        );
    }

}
profile
공부했던 내용들을 모아둔 창고입니다.

0개의 댓글