[01.26] 내일배움캠프[Spring] TIL-59

박상훈·2023년 1월 26일
0

내일배움캠프[TIL]

목록 보기
59/72

[01.26] 내일배움캠프[Spring] TIL-59

1. Test Code

  • TDD -> Test Code먼저 작성하고 실제 로직을 작성하는 방식으로 아직 찬반 여부 갈림.

UserService Test Code

@ExtendWith(MockitoExtension.class)// junit과 mockito를 연결
class UserServiceImplTest {

    @Mock
    private UserRepository userRepository;

    @Mock
    private ProfileRepository profileRepository;

    @Mock
    private PointRepository pointRepository;

    @Mock
    private JwtUtil jwtUtil;

    @InjectMocks
    private UserServiceImpl userService;

    @Spy
    private BCryptPasswordEncoder passwordEncoder;

    @Test
    @DisplayName("회원 가입성공")
    void signup() {

        //given
        SignupDto signupDto = SignupDto.builder()
                .username("asd1234")
                .password("asd12345!")
                .nickname("일반유저")
                .admin(false)
                .build();

        //가짜 객체의 리턴값을 만들어주는 작업
        when(userRepository.findByUsername(any(String.class)))
                .thenReturn(Optional.empty());


        //when
        String msg = userService.signup(signupDto);

        //then
        assertThat(msg).isEqualTo("회원가입 성공");

    }

    @Test
    @DisplayName("회원 가입실패")
    void signupFail() {

        //given
        SignupDto signupDto = SignupDto.builder()
                .username("asd1234")
                .password("asd12345!")
                .nickname("일반유저")
                .admin(false)
                .build();

        //가짜 객체의 리턴값을 만들어주는 작업
        when(userRepository.findByUsername(any(String.class)))
                .thenReturn(Optional.ofNullable(User.builder()
                        .username("asd1234")
                        .password("asd12345!")
                        .role(UserRoleEnum.CUSTOMER)
                        .build())
                );


        //when
//        String msg = userService.signup(signupDto);


        //then
        assertThatThrownBy(
                () -> userService.signup(signupDto)
        ).isInstanceOf(IllegalArgumentException.class)
                .hasMessage("유저가 존재합니다");

    }

    @Test
    @DisplayName("로그인")
    void login() {

        //given

        LoginUserRequestDto loginUserRequestDto = LoginUserRequestDto.builder()
                .username("asd1234")
                .password("asd12345!")
                .build();


        User user = User.builder()
                .username("asd1234")
                .password(passwordEncoder.encode("asd12345!"))
                .role(UserRoleEnum.CUSTOMER)
                .build();

        //HttpServlet을 위한 객체
        MockHttpServletResponse mockHttpServletResponse = new MockHttpServletResponse();

        when(userRepository.findByUsername(any(String.class)))
                .thenReturn(Optional.of(user));
        //when

        String msg = userService.login(loginUserRequestDto,mockHttpServletResponse);
        String token = jwtUtil.createToken(any(),any());

        //then
        assertThat(msg).isEqualTo("로그인 성공");
       // assertThat(mockHttpServletResponse.getHeaderValue("Authorization").toString()).isNotEmpty();

        //어떤 함수가 몇번 불려졌냐? 행위검증
        //verify(userRepository,times(1)).saveAndFlush(any(User.class));
    }
}

Problem / Solve

  • 회원가입 : 성공 케이스는 어찌저찌 잘 작성했는데, 실패 케이스를 작성할 때
    asserThatThrowBy로 IllegalArgumentException()과 그 메세지를 비교할 때 생각보다 시간이 오래 걸렸다.
  • 로그인 : 사실 로그인은 그냥 로그인이 잘 되는지 안되는지의 목적이지 Jwt토큰이 잘 발행 되는지 의무를 확인 할 필요는 없다는 사실을 뒤늦게 깨달았다.
  • 그리고 JwtToken을 만들 Key를 @PostContstruct에서 init()해주는데, @Spy가 실제 로직을 그대로 실행한다고 해서 사용했지만, 작동하지 않아서 계속 Key값이 들어가지 않았다.
  • 기존의 코드를 수정하는 것 이지만 JwtUil에 @PostConstruct에서 하던 작업을 기본 생성자에 넣어서 해결하는 방법도 있다.
  • 다른 분들은 @Spy해서도 @PostConstruct가 돌아가게 할 수 있다고 하셨는데, 조금더 공부가 필요한 것 같다.

ProductService Test Code

@ExtendWith(MockitoExtension.class)
class ProductServiceImplTest {


    @Mock
    private ProductRepository productRepository;



    @InjectMocks
    private ProductServiceImpl productService;
    @Test
    @DisplayName("상품추가")
    void addProduct() {

        //given
        ProductRequestDto productResponseDto = new ProductRequestDto();

        User user = new User();


        //when
        String msg = productService.addProduct(productResponseDto,user);

        //then
        assertThat(msg).isEqualTo("해당 상품을 등록 완료했습니다");

        verify(productRepository,times(1)).save(any(Product.class));

    }

    @Test
    @DisplayName("상품 정보 수정 정상")
    void updateProduct()  {
        //given

        ProductUpdateRequestDto productUpdateRequestDto = new ProductUpdateRequestDto(7777);

        User user = mock(User.class);

        Product product = Product.builder().productName("computer").price(1000).build();
        //given(user.checkUser(anyLong())).willReturn(true);
        given(user.checkUser(anyLong())).willReturn(true);
        given(productRepository.findById(anyLong())).willReturn(Optional.ofNullable(product));
        //when

       String msg = productService.updateProduct(anyLong(),productUpdateRequestDto,user);
        //then
        assertThat(msg).isEqualTo("해당 제품의 가격이 업데이트 되었습니다");
    }

    @Test
    @DisplayName("상품내역 전체보기")
    void showProductList() {

        //given
        PageDto pageDto = new PageDto(1,1,"id",true);
        Pageable pageable = productService.makePage(pageDto);
        given(productRepository.findAll(pageable)).willReturn(Page.empty());

        //when

        Page<ProductResponseDto> products = productService.showProductList(pageDto);
        //then
        verify(productRepository,times(1)).findAll(pageable);
        assertThat(products).isEmpty();

    }
}

Problem / Solve

  • 상품등록 : 별다른 문제는 없었다. 다만 이 비즈니스 로직을 실행했을 때의 기대 값에 대한 것이 없고 그냥 저장! 이기 때문에, save()메서드가 1번 실행되는 것이 맞는지 verify()로 확인했다.
  • 상품 정보 수정 : 여기선 아주 큰 깨달음이 있었다.
    현재 우리의 TestCode 작업은 기존에 완성했던 프로젝트를 가지고 한다는 사실을 망각했다.
    user.checkUser(long)으로 그 유저가 맞을 시 update()를 하는 로직인데, 이 것또한 Test해봐야 한다고 생각해서 처음에는 User를 생성자 형태로 변수를 다 할당해서 만들어 줬다.
    -> 그랬더니 계속 인식하지 못했고, 오히려 User user = new User(.....)만! 넣었을 때는 기대 값이 나왔다.
  • 해결 : User객체를 Mock으로 만들고, 그 객체를 검증하는 부분 또한 given ~ willReturn으로 줬을 때 비로소 해결했다.
    -> 정리 : 객체 자체안에 검증하는 로직이 들어가고 그것을 테스트 해보고싶다면, 그 객체를 Mock객체로 만들어, 그 검증 로직 또한 선언해주자...!
    -> 그냥 User user = new User(.....) 이런식으로 객체를 생성하고 그것으로 테스트한다면, 그냥 검증이 잘 된 상태로 돌아간다!

요약

  • 어떨 때는 when ~ ThenReturn / given ~ willReturn ??
    -> TDD / BDD 인데 사실 given // when // then// 딴에서 given 구문에 when절이 들어가서 가독성이 떨어지고, 혼란을 야기 했기 때문에 등장..!
  • 객체안에 검증이나 다른 로직이 필요할 땐, Mock객체로 만들어서 쓰자..!
profile
기록하는 습관

0개의 댓글