스터디 기록/SpringBoot 심화 스터디

서비스 테스트와 컨트롤러 테스트

drinkgalaxy 2024. 11. 19. 18:52

서비스 테스트

보통 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

결과를 원하는 대로 검증한다. 응답 상태 코드를 확인할 수 있다.