Unit Test 1일차

5w31892p·2023년 1월 26일
0

테스트코드

목록 보기
1/2

:: 단위테스트

  • 메서드 단위로 테스트를 수행
  • contlroller, service, repository 따로

:: 통합테스트

  • 애플리케이션 동장하는지 테스트 -> 포스트맨
  • controller method 호출하면 controller, service, repository 모두 수행

:: F.I.R.S.T 원칙

  • Fast : 단위 테스트는 빨라야 한다.
  • Independent : 단위 테스트는 독립적이어야 한다.
  • Repeatable : 단위테스트는 반복 가능해야한다. 반복적으로 테스트를 시행해도, 결과는 같아야 한다.
  • Self-validating : 자체적으로 테스트 결과가 도출되야한다. (자동으로 수행되며 성공/실패 의 결과가 나오는 것)
  • Timely : 단위 테스트는 실제 코드보다 먼저 구현해야한다. (TDD만 해당)

:: Given-When-Then 패턴

  • Given : 테스트에 필요한 변수 정의 or Mock 객체를 통해 특정 상황에 대한 행동을 정의
  • When: 실제 테스트를 하는 메소드가 호출되며 테스트를 통한 결과값 도출
  • Then: When 단계에서 나온 결과값을 검증

:: Mockito

  • Mockito : Mock 객체를 쉽게 만들고, 관리하고, 검증할 수 있는 방법을 제공하는 프레임워크 입니다. Mock 객체는 진짜 객체와 비슷하게 동작하지만 프로그래머가 직접 행동을 관리하는 객체입니다.

    • @Mock: Mock 객체를 만들어 반환해주는 어노테이션
    • @Spy: Stub하지 않은 메소드들은 원본 메소드 그대로 사용하는 어노테이션
    • @InjectMocks: @Mock 또는 @Spy로 생성된 가짜 객체를 자동으로 주입시켜주는 어노테이션

@ExtendWith(MockitoExtension.class) : JUnit 과 Mockito 연결
@Mock: 가짜! -> repository ..
@Spy : 진짜! -> jwt, password ..
@injectMocks : mock이든 spy이든 여기다 주입

given : when에서 사용할 파라미터 지정 -> RequestDto
when : 진짜 테스트 시작
then : 검증

HttpServletResponse or HttpServletRequest 와 같은 경우는 앞에 Mock 을 붙혀 사용 하면 된다. -> given

:: UserServiceTest

package com.sparta.blogproject.user.service;

import com.sparta.blogproject.common.jwt.JwtUtil;
import com.sparta.blogproject.user.dto.LoginRequest;
import com.sparta.blogproject.user.dto.ResponseStatusDto;
import com.sparta.blogproject.user.dto.SignupRequest;
import com.sparta.blogproject.user.dto.StatusEnum;
import com.sparta.blogproject.user.entity.User;
import com.sparta.blogproject.user.repository.UserRepository;
import org.junit.jupiter.api.DisplayName;
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 org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.Optional;

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

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Spy
    private JwtUtil jwtUtil;

    @Spy
    private BCryptPasswordEncoder passwordEncoder;

    @Test
    @DisplayName("회원 가입")
    void signup() {
        // given
        SignupRequest request = SignupRequest.builder()
                .admin(false)
                .username("nathan")
                .password("1234qwer")
                .email("nathan@gmail.com")
                .build();

        when(userRepository.findByUsername(any(String.class)))
                .thenReturn(Optional.empty());

        // when
        ResponseStatusDto response = userService.signup(request);

        // then
        assertThat(response.getStatusCode()).isEqualTo(StatusEnum.SIGN_SUCCESS.getStatusCode());
        assertThat(response.getMsg()).isEqualTo(StatusEnum.SIGN_SUCCESS.getMsg());
    }

    @Test
    @DisplayName("로그인")
    void login() {
        // given
        LoginRequest request = LoginRequest.builder()
                .username("nathan")
                .password("1234qwer")
                .build();

        User user = new User("nathan", passwordEncoder.encode("1234qwer"), null, null);

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

        MockHttpServletResponse servletResponse = new MockHttpServletResponse();

        // when
        ResponseStatusDto response = userService.login(request, servletResponse);

        // then
        assertThat(response.getStatusCode()).isEqualTo(StatusEnum.LOGIN_SUCCESS.getStatusCode());
        assertThat(response.getMsg()).isEqualTo(StatusEnum.LOGIN_SUCCESS.getMsg());
        assertThat(servletResponse.getHeaderValue("Authorization").toString()).isNotEmpty();

        verify(userRepository).saveAndFlush(any(User.class));
    }
}


void와 같이 리턴값이 없을 때에는 verify로 하면 된다. id는 anylong()

:: ProductServiceTest

package com.sparta.blogproject.post.service;

import com.sparta.blogproject.post.dto.PostRequestDto;
import com.sparta.blogproject.post.dto.PostResponseDto;
import com.sparta.blogproject.post.entity.Post;
import com.sparta.blogproject.post.repository.PostRepository;
import com.sparta.blogproject.user.entity.User;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class PostServiceTest {

    @Mock
    private PostRepository postRepository;

    @InjectMocks
    private PostService postService;

    @Test
    void createPost() {

        // given
        PostRequestDto request = new PostRequestDto();
        User user = new User();

        // when
        postService.createPost(request, user);

        // then
        verify(postRepository).save(any(Post.class));
    }

    @Test
    void getPosts() {
        // given
        Pageable pageable = Pageable.ofSize(20);
        when(postRepository.findAll(pageable)).thenReturn(Page.empty());

        // when
        Page<PostResponseDto> response = postService.getPosts(pageable);

        // then
        assertThat(response).isEmpty();

        // verify
        verify(postRepository).findAll(pageable); // findAll이 호출 되었는가?
    }

    @Test
    @DisplayName("게시글 id가 없을때 예외 발생")
    void getPostById_throw() {
        // given
        when(postRepository.findById(anyLong())).thenReturn(Optional.empty()); 

        // when & then
        assertThrows(IllegalArgumentException.class, () -> {
            postService.getPostById(0L);
        }); // 	다른 예외로 지정시 실패
    }

    @Test
    @DisplayName("게시글 가져오기")
    void getPostById() {
        // given
        PostRequestDto request = PostRequestDto.builder()
                .contents("hello.. hello..")
                .title("hello")
                .build();

        Post post = new Post(request, new User());
        when(postRepository.findById(anyLong())).thenReturn(Optional.of(post)); //id가 테스트 할 때에는 의미가 없기 때문에 anylong

        // when
        PostResponseDto response = postService.getPostById(anyLong());

        // then
        assertThat(response.getContents()).isEqualTo(request.getContents());
        assertThat(response.getTitle()).isEqualTo(request.getTitle());

        // verify
        verify(postRepository, times(1)).findById(anyLong());
    }

    @Test
    @DisplayName("게시글 업데이트")
    void updatePost() {
        // given
        PostRequestDto request = PostRequestDto.builder()
                .contents("hello.. hello..")
                .title("hello")
                .build();
        User user = new User("nathan", "1234qwer", null, null);
        Post post = new Post(request, user);

        when(postRepository.findById(anyLong())).thenReturn(Optional.of(post));

        // when
        postService.updatePost(anyLong(), request, user);

        // verify
        verify(postRepository, times(1)).save(any(Post.class));
    }

    @Test
    @DisplayName("게시글 업데이트 (다른 사람이 작성하려할때)")
    void updatePost_invalid_user() {
        // given
        PostRequestDto request = PostRequestDto.builder()
                .contents("hello.. hello..")
                .title("hello")
                .build();
        User userInPost = new User("nathan", "1234qwer", null, null);
        User userInput = new User("joel", "1234qwer", null, null);
        Post post = new Post(request, userInPost);

        when(postRepository.findById(anyLong())).thenReturn(Optional.of(post));

        // when & then
        assertThrows(IllegalArgumentException.class, () -> postService.updatePost(anyLong(), request, userInput));
    }
}

0개의 댓글