Junit Test Application-29-계좌등록 JUnit 테스트

jaegeunsong97·2023년 8월 6일
0

Junit Bank Application 깃허브

Junit Bank Application 기록 노션

서비스 테스트

package shop.mtcoding.bank.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import java.util.Optional;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import com.fasterxml.jackson.databind.ObjectMapper;

import shop.mtcoding.bank.config.dummy.DummyObject;
import shop.mtcoding.bank.domain.account.Account;
import shop.mtcoding.bank.domain.account.AccountRepository;
import shop.mtcoding.bank.domain.user.User;
import shop.mtcoding.bank.domain.user.UserRepository;
import shop.mtcoding.bank.dto.account.AccountRequestDto.AccountSaveRequestDto;
import shop.mtcoding.bank.dto.account.AccountResponseDto.AccountSaveResponseDto;

@ExtendWith(MockitoExtension.class)
public class AccountServiceTest extends DummyObject {

     @InjectMocks
     private AccountService accountService;
     @Mock
     private UserRepository userRepository;
     @Mock
     private AccountRepository accountRepository;
     @Spy
     private ObjectMapper om;

     @Test
     public void 계좌등록_test() throws Exception {
          // given
          Long userId = 1L;

          AccountSaveRequestDto accountSaveRequestDto = new AccountSaveRequestDto();
          accountSaveRequestDto.setNumber(1111L);
          accountSaveRequestDto.setPassword(1234L);

          // stub 1
          User ssar = newMockUser(userId, "ssar", "쌀");
          when(userRepository.findById(any())).thenReturn(Optional.of(ssar));

          // stub 2
          when(accountRepository.findByNumber(any())).thenReturn(Optional.empty());

          // stub 3
          Account ssarAccount = newMockAccout(1L, 1111L, 1000L, ssar);
          when(accountRepository.save(any())).thenReturn(ssarAccount);

          // when
          AccountSaveResponseDto accountSaveResponseDto = accountService.계좌등록(accountSaveRequestDto, userId);
          String resposneBody = om.writeValueAsString(accountSaveResponseDto);
          System.out.println("테스트 : " + resposneBody);

          // then
          assertThat(accountSaveRequestDto.getNumber()).isEqualTo(1111L);
     }
}

컨트롤러 테스트

package shop.mtcoding.bank.web;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.databind.ObjectMapper;

import shop.mtcoding.bank.dto.account.AccountRequestDto.AccountSaveRequestDto;

@ActiveProfiles("test") // 테스트 모드
@Transactional
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class AccountControllerTest {

     @Autowired
     private MockMvc mvc;
     @Autowired
     private ObjectMapper om;

     @Test
     public void saveAccount_test() throws Exception {
          // given
          AccountSaveRequestDto accountSaveRequestDto = new AccountSaveRequestDto();
          accountSaveRequestDto.setNumber(9999L);
          accountSaveRequestDto.setPassword(1234L);
          String requestBody = om.writeValueAsString(accountSaveRequestDto);
          System.out.println("테스트 : " + requestBody);

          // when
          ResultActions resultActions = mvc.perform(post("/api/s/account")
                    .content(requestBody).contentType(MediaType.APPLICATION_JSON));
          String resopnseBody = resultActions.andReturn().getResponse().getContentAsString();
          System.out.println("테스트 : " + resopnseBody);

          // then

     }
}

로그인을 하면된다.

우리가 JWT로 로그인을 할 필요가 없다.

JWT token -> 인증필터 -> 시큐리티 세션 생성

즉 /api/s/account는 시큐리티 세션만 있으면 통과가 가능하다는 것이다.

"로그인을 진행해 주세요" 이부분은 SecurityConfig에서 터진 것이다.

즉 AuthorizationFilter 인가를 통과한 것이다.

그러면 헤더를 안 넣었는데 어떻게 통과를 하는거지? 라는 생각이 들 수 있다.

JWT 토큰 헤더를 가지지 않아도 필터는 통과하지만, 시큐리티 단에서 세션 값 검증에 실패할 것이다.

코드를 보면 토큰이 없으면 chain.doFilter가 실행되서 controller로 진입은 할 것이다. 컨트롤러에서 /api/s/ 부분에서 막히게 되는 것이다.

그리고 나서 아래 부분에서 막히게 되는 것이다.

따라서 테스트를 할 때 토큰을 생성할 필요는 없고 시큐리티 세션을 강제 생성만 하면 된다.

@WithUserDetails(value = "ssar")
     @Test
     public void saveAccount_test() throws Exception {

터지는 이유 : @WithUserDetails, DB에서 username = ssar 조회를 해서 세션에 담아주는 어노테이션

근데 DB에는 ssar이 없다. 따라서 조회했는데 없기 때문에 터진 것이다.

DB에 ssar을 넣어주면 된다.

그래도 터진다.

이유 : setupbefore = TEST_METHOD, setUp 메서드 실행 전에 수행

따라서 @WithUserDetails이 먼저 동작하는 것이기 때문에 터진다.

그러면 setUp 이후에 @WithUserDetails이 동작하게 만들면 된다

@WithUserDetails(value = "ssar", setupBefore = TestExecutionEvent.TEST_EXECUTION)
     @Test
     public void saveAccount_test() throws Exception {

이렇게 되면 setUp을 통해 ssar이 DB에 저장, @WithUserDetails를 통해 ssar을 DB에서 조회후 세션에 넣는다. 이렇게 되면 인증쪽은 간단하가.

결론 : 컨트롤러 인증 부분 테스트 , setUp() + @WithUserDetails(value = "ssar", setupBefore = TestExecutionEvent.TEST_EXECUTION)

  • 완성 코드
package shop.mtcoding.bank.web;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.TestExecutionEvent;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.databind.ObjectMapper;

import shop.mtcoding.bank.config.dummy.DummyObject;
import shop.mtcoding.bank.domain.user.UserRepository;
import shop.mtcoding.bank.dto.account.AccountRequestDto.AccountSaveRequestDto;

@ActiveProfiles("test") // 테스트 모드
@Transactional
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class AccountControllerTest extends DummyObject {

     @Autowired
     private MockMvc mvc;
     @Autowired
     private ObjectMapper om;
     @Autowired
     private UserRepository userRepository;

     @BeforeEach
     public void setUp() {
          userRepository.save(newUser("ssar", "쌀"));
     }

     @WithUserDetails(value = "ssar", setupBefore = TestExecutionEvent.TEST_EXECUTION)
     @Test
     public void saveAccount_test() throws Exception {
          // given
          AccountSaveRequestDto accountSaveRequestDto = new AccountSaveRequestDto();
          accountSaveRequestDto.setNumber(9999L);
          accountSaveRequestDto.setPassword(1234L);
          String requestBody = om.writeValueAsString(accountSaveRequestDto);
          System.out.println("테스트 : " + requestBody);

          // when
          ResultActions resultActions = mvc.perform(post("/api/s/account")
                    .content(requestBody).contentType(MediaType.APPLICATION_JSON));
          String resopnseBody = resultActions.andReturn().getResponse().getContentAsString();
          System.out.println("테스트 : " + resopnseBody);

          // then
          resultActions.andExpect(status().isCreated());
     }
}

profile
블로그 이전 : https://medium.com/@jaegeunsong97

0개의 댓글