SRP
를 잘 지키고, 크기가 적절히 작아야 함Mocking
을 통한 격리성 확보refactoring
, 기법에 대한 고민 등)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
테스트용 객체, request
를 refactoring
하여 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로 나타난 실제 결과값)
: 예상값과 실제 결과값 비교service
의 createdIdol
테스트
// @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)
);
}
}