서비스 테스트와 컨트롤러 테스트
서비스 테스트
보통 Mock 테스트를 진행한다.
테스트할 서비스 클래스에는 @InjectMocks 어노테이션을 달아준다. 여기 Mock 객체들을 주입할 것이다.
나머지 레포지토리, 서비스는 가짜 객체를 생성하 @Mock 어노테이션을 달아준다.
진짜 객체를 InjectMocks에 주입하고 싶으면 @Spy 어노테이션을 달아주면 된다.
@ExtendWith(MockitoExtension.class) // 전체를 띄울 필요 없고, 내가 원하는 것만 띄울 때 ExtendWith 사용
public class AccountServiceTest extends DummyObject {
@InjectMocks // 모든 Mock 들이 InjectMocks 로 주입됨
private AccountService accountService;
@Mock
private UserRepository userRepository;
@Mock
private AccountRepository accountRepository;
@Spy // 진짜 객체를 InjectMocks 에 주입한다.
private ObjectMapper om;
@Test
public void accountResister_test() throws Exception {
// given
Long userId = 1L;
AccountReqDto.AccountSaveReqDto accountSaveReqDto = new AccountReqDto.AccountSaveReqDto();
accountSaveReqDto.setNumber(1111L);
accountSaveReqDto.setPassword(1234L);
// stub 1
User ssar = newMockUser(1L, "ssar", "쌀");
when(userRepository.findById(any())).thenReturn(Optional.of(ssar));
// stub 2
when(accountRepository.findByNumber(any())).thenReturn(Optional.empty());
// exception 이 안 터져야 잘 된거니까 empty 를 리턴함.
// stub 3
Account ssarAccount = newMockAccount(1L, 1111L, 1000L, ssar);
when(accountRepository.save(any())).thenReturn(ssarAccount);
// when
AccountResDto.AccountSaveResDto accountSaveResDto = accountService.accountRegister(accountSaveReqDto, userId);
String responseBody = om.writeValueAsString(accountSaveResDto);
System.out.println("테스트 = "+ responseBody);
// then
assertThat(accountSaveResDto.getNumber()).isEqualTo(1111L);
}
1) given
더미데이터를 설정하거나 서비스 테스트에 필요한 reqDto를 정의한다.
1-1)
서비스 로직에 필요한 stub 데이터를 준비해준다.
2) when
실제 서비스를 실행하고 결과를 반환한다.
3) then
결과를 원하는 대로 검증한다.
컨트롤러 테스트
보통 SpringBoot Test를 진행한다.
이때 @AutoConfigureMockMvc 어노테이션을 붙여주면, 실제 서버를 띄우지 않고 컨트롤러 테스트를 더 쉽게 하도록 돕는다.
즉, HTTP 요청과 응답을 흉내 내어 애플리케이션을 테스트할 수 있게 도와준다.
실제 객체를 주입받기 위해 @Autowired 어노테이션을 달아준다.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class AccountControllerTest extends DummyObject {
@Autowired
private ObjectMapper om;
@Autowired
MockMvc mvc;
@Autowired
private UserRepository userRepository;
@Autowired
private AccountRepository accountRepository;
@Autowired
private EntityManager em;
@BeforeEach
public void setUp() {
dataSetting();
em.clear(); // 영속성 컨텍스트 청소
}
// jwt token -> 인증필터 -> 시큐리티 세션 생성 (= 그니까 한마디로 로그인을 진행해줌.)
@WithUserDetails(value = "ssar", setupBefore = TestExecutionEvent.TEST_EXECUTION)
@Test
public void saveAccount_test() throws Exception {
// given
AccountReqDto.AccountSaveReqDto accountSaveReqDto = new AccountReqDto.AccountSaveReqDto();
accountSaveReqDto.setNumber(9999L);
accountSaveReqDto.setPassword(1234L);
String requestBody = om.writeValueAsString(accountSaveReqDto);
System.out.println("테스트 = "+ requestBody);
// when
ResultActions resultActions = mvc.perform(post("/api/s/account").content(requestBody).contentType(MediaType.APPLICATION_JSON));
String responseBody = resultActions.andReturn().getResponse().getContentAsString();
System.out.println("테스트 = "+ responseBody);
// then
resultActions.andExpect(status().isCreated());
}
- 더미 데이터 세팅 후에 테스트를 시작할 때 마다 영속성 컨텍스트를 새롭게 청소해주는 것이 좋다.
- @WithUserDetails(value = "ssar", setupBefore = TestExecutionEvent.TEST_EXECUTION) :
- db에서 username = ssar 조회를 해서 세션에 담아주는 어노테이션이다. 즉, 시큐리티 세션을 생성해 한마디로 로그인을 진행해준다.
- setupBefore에 TestExecutionEvent.TEST_EXECUTION 을 명시하면 모든 테스트 메서드 실행 전에 로직을 수행한다. 따라서 로그인 이후 실행이 필요한 테스트들에 유용하게 사용할 수 있다.
- 참고로 db에 username = ssar 인 데이터가 없으면 에러가 터진다.
1) given
테스트에 필요한 데이터를 준비한다. 필요하다면 ObjectMapper를 사용해 responseBody를 찍어볼 수 있다.
2) when
mvc.perform으로 실제 api를 호출하고, ResultActions에 결과를 담아올 수 있다.
3) then
결과를 원하는 대로 검증한다. 응답 상태 코드를 확인할 수 있다.