2024.10.06.(일)

4주차

테스트 코드란?

  • 테스트 코드의 필요성
  1. 테스트 시간이 빠르다 -> 테스트코드 없이 Postman과 같은 API 테스트 도구로 테스트 하면 다음과 같은 과정을 반복한다.

프로그램 실행 -> Postman 으로 HTTP 요청 후 확인 또는 결과를 콘솔에서 확인 -> 서버를 내린 뒤 다시 코드를 수정

-> 이 과정들을 반복한다면 생각보다 많은 시간을 쓰게 된다. 테스트 코드를 사용하게 된다면 빠른 시간 안에 여러 테스트 결과를 확인할 수 있다.

  1. 자동 검증이 가능하다.

    -> Postman을 쓴다면 결과가 잘 넘어왔는지 사람 눈으로 판단한다. 대형 프로젝트에서는 실수가 발생할 수 있다. 반면 테스트 코드를 작성한다면 결과를 자동으로 검증해준다.

  2. 기존 기능의 정상 동작을 보장한다.

    -> 코드를 수정하면 프로젝트가 클 경우 사이드 이펙트가 발생할 수 있다. 테스트 코드를 사용해서 다른 부분에서 문제가 발생하지 않은지 바로 알 수 있다.

이런 이유들로 많은 사람들이 테스트 코드 작성을 필수로 여긴다. 이번 시간에는 테스트를 간단히 작성해보는 시간을 가질 것이다.

  • 테스트의 종류

단위 테스트: 소프트웨어에서 테스트할 수 있는 가장 작은 단위를 테스트한다. 서비스 별, 도메인 별, 레포지터리 별로 단위 테스트 코드를 작성할 수 있다.

통합 테스트: 테스트하려는 코드가 다른 코드(의존관계)와 잘 연동이 되었는지 테스트한다. 주로 프레임워크와 데이터베이스의 연동을 테스트한다.

간단히 말하자면 데이터베이스가 필요하면 통합 테스트를 진행하고, 필요하지 않으면 단위 테스트를 진행한다.

테스트 코드 작성하기

간단한 통합 테스트를 작성해보자. 로컬은 MySQL로 실행되도록 설정해놓았다. 매번 MySQL을 실행시키기 번거로우므로 테스트 환경을 H2로 설정했다.

// test/resources/application.yml
spring:
  datasource:
    url: jdbc:h2:mem:test;NON_KEYWORDS=USER
    driverClassName: org.h2.Driver
    username: sa
    password:


  jpa:
    hibernate:
      ddl-auto: create-drop
    database-platform: org.hibernate.dialect.H2Dialect

@SpringBootTest: 스프링부트를 통합 테스트로 실행한다. 실제 스프링 환경에서 테스트하게 만들어주는 어노테이션이라고 생각하자

@AutoConfigureMockMvc: MockMvc를 자동으로 설정해주는 어노테이션. HTTP 요청을 모킹할 수 있다. Mock: 가짜 객체

@BeforeEach, @AfterEach: 각 테스트 전과 후에 실행되는 메서드로, 데이터베이스를 초기화하여 테스트 간의 데이터를 분리하는데 사용한다.

@Test 및 @DisplayName: 실제 테스트를 실행하는 메서드와 해당 테스트에 대한 설명을 지정

@Autowired: 객체를 자동으로 주입하는 어노테이션이다. 외부 설정파일을 작성하지 않아도 되게 만들어준다. 단, 빈에 등록되어 있는 객체만 가능하다.

테스트 코드를 한눈에 알아보기 쉽게 하기 위해 given-expected로 나누었다. 주어진 상황과 기대되는 결과를 나누었다고 생각하면 된다.

// test/../controller/UserControllerTest
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private UserRepository userRepository;

    @BeforeEach
    void clean() {
        userRepository.deleteAll();
    }

    @Test
    @DisplayName("회원가입")
    void test1() throws Exception {

        // given
        SignupRequest signup = SignupRequest.builder()
                .email("nmkk1234@naver.com")
                .password1("1234")
                .password2("1234")
                .username("kim")
                .build();

        // expected
        mockMvc.perform(post("/api/user/signup")
                    .content(objectMapper.writeValueAsString(signup))
                    .contentType(APPLICATION_JSON))
                .andExpect(status().isCreated())
                .andDo(print());
    }
}

테스트 코드를 한눈에 알아보기 쉽게 하기 위해 given-when-then 으로 나누었다. 주어진 조건 - 주어진 상황 - 예상 결과로 생각하면 된다.

주의: assertj 대신 junit을 사용해야 한다!!

// test/../service/UserServiceTest
@SpringBootTest
public class UserServiceTest {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserService userService;

    @AfterEach
    void clean() {
        userRepository.deleteAll();
    }

    @Test
    @DisplayName("회원가입 성공")
    void test1() {
        //given
        SignupRequest signup = SignupRequest.builder()
                .email("nmkk1234@naver.com")
                .password1("1234")
                .password2("1234")
                .username("kim")
                .build();

        // when
        userService.signup(signup);

        // then
        assertEquals(1, userRepository.count());

        User user = userRepository.findAll().iterator().next();
        assertEquals("nmkk1234@naver.com", user.getEmail());
        assertNotNull(user.getPassword());
        assertNotEquals("1234", user.getPassword());
        assertEquals("kim", user.getUsername());
    }

    @Test
    @DisplayName("회원가입시 중복된 이메일")
    void test2() {

        // given
        User user = User.builder()
                .email("nmkk1234@naver.com")
                .password("12345")
                .username("kim")
                .build();

        userRepository.save(user);

        // when
        SignupRequest signup = SignupRequest.builder()
                    .email("nmkk1234@naver.com")
                    .password1("1234")
                    .password2("1234")
                    .username("kim2")
                    .build();

        // expected
        assertThrows(AlreadyExistsEmailException.class,
        () -> userService.signup(signup));
    }
}