반응형

가독성 높이는 습관 - 테스트 코드 - 실습

 

 

실습

  • 상태 테스트
  • 행위 테스트
  • 성송 & 실패 테스트

 

 

package com.example.zerobase.domain;

import com.example.zerobase.type.ZerobaseCourseStatus;
import com.example.zerobase.web.exception.ExceptionCode;
import com.example.zerobase.web.exception.ZerobaseException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ZerobaseCourseQueryService {
    private final ZerobaseCourseRepository zerobaseCourseRepository;

    public ZerobaseCourse getOrThrow(Long id) {
        return zerobaseCourseRepository.findById(id)
                .filter(it -> !it.isHidden())
                // TODO 적당히 Exception을 바꿔보세요
                .orElseThrow(() -> new ZerobaseException(ExceptionCode.NOT_FOUND_COURSE)); 
    }

    public List<ZerobaseCourse> getZerobaseCourseList(ZerobaseCourseStatus status) {

        checkStatus(status);

        return zerobaseCourseRepository.findAll()
                .stream()
                .filter(it -> !it.isHidden())
                .filter(it -> it.isSameStatus(status))
                .collect(Collectors.toList());
    }

    private void checkStatus(ZerobaseCourseStatus status) {
        if (status.isUnknown())
            // TODO 적당히 Exception을 바꿔보세요
            throw new ZerobaseException(ExceptionCode.INVALID_COURSE_STATUS); 

        if (status.isClose())
            // TODO 적당히 Exception을 바꿔보세요
            throw new ZerobaseException(ExceptionCode.ALREADY_CLOSED); 
    }
}
package com.example.zerobase.web.advice;

import com.example.zerobase.web.exception.ExceptionCode;
import com.example.zerobase.web.exception.ZerobaseException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    // TODO : 익셉션 핸들러를 작성하세요
    @ExceptionHandler(value = ZerobaseException.class)
    public ResponseEntity<ErrorResult> runtimeException(ZerobaseException e) {
        ExceptionCode errorCode = e.getCode();
        ErrorResult result = ErrorResult.builder()
                .code(errorCode.name())
                .message(e.getMessage())
                .build();
        return new ResponseEntity(result, errorCode.getStatus()); }
}
package com.example.zerobase.web;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;

import static com.example.zerobase.web.exception.ExceptionCode.*;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@ActiveProfiles("test")
@SpringBootTest
@AutoConfigureMockMvc
public class ZeroBaseCourseControllerTest {

    private MockMvc mockMvc;

    @BeforeEach
    void setUp(WebApplicationContext ctx) {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx)
                .addFilters(new CharacterEncodingFilter("UTF-8", true))
                .alwaysDo(print())
                .build();
    }

    @DisplayName("❗️강의 단건조회 api 테스트")
    @ParameterizedTest(name = "/v1/api/course/{arguments} 테스트")
    @ValueSource(longs = {1, 2, 3, 4, 5})
    public void success__getZerobaseCourse(long id) throws Exception {
        mockMvc.perform(get("/v1/api/course/" + id).contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id", notNullValue()))
                .andExpect(jsonPath("$.name", notNullValue()))
                .andExpect(jsonPath("$.start_at", notNullValue()))
                .andExpect(jsonPath("$.end_at", notNullValue()));
    }

    @DisplayName("❗강의 단건조회 실패 api 테스트")
    @ParameterizedTest(name = "/v1/api/course/{arguments} 테스트")
    @ValueSource(longs = {-1, 0, 6, 7, Long.MAX_VALUE})
    public void fail__getZerobaseCourse(long id) {
        assertThatThrownBy(() -> mockMvc.perform(get("/v1/api/course/" + id).contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().is5xxServerError())
                .andExpect(jsonPath("$.code", is(NOT_FOUND_COURSE.name())))
                .andExpect(jsonPath("$.message", is(NOT_FOUND_COURSE.getMessage()))));
    }

    @DisplayName("❗강의 다건조회 api 테스트")
    @ParameterizedTest(name = "/v1/api/course?status={arguments} 테스트")
    @ValueSource(strings = {"OPEN", "IN_PROGRESS"})
    public void success__getZerobaseCourses(String status) throws Exception {
        mockMvc.perform(get("/v1/api/course?status=" + status).contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.*", hasSize(2)))
                .andExpect(jsonPath("$.[*].status", Matchers.everyItem(is(status))));
    }

    @DisplayName("❗강의 다건조회 실패 api 테스트(CLOSE)")
    @ParameterizedTest(name = "/v1/api/course?status=CLOSE 테스트")
    @ValueSource(strings = {"CLOSE"})
    public void fail____getZerobaseCourses() {
        assertThatThrownBy(() -> mockMvc.perform(get("/v1/api/course?status=CLOSE").contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().is5xxServerError())
                .andExpect(jsonPath("$.code", is(ALREADY_CLOSED.name())))
                .andExpect(jsonPath("$.message", is(ALREADY_CLOSED.getMessage()))));
    }

    @DisplayName("❗강의 다건조회 실패 api 테스트(INVALID)")
    @ParameterizedTest(name = "/v1/api/course?status={arguments} 테스트")
    @ValueSource(strings = {"INVALID", "HELLO", "FOO", "", "1111"})
    public void fail____getZerobaseCourses(String status) {
        assertThatThrownBy(() -> mockMvc.perform(get("/v1/api/course?status=" + status).contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().is4xxClientError())
                .andExpect(jsonPath("$.code", is(INVALID_COURSE_STATUS.name())))
                .andExpect(jsonPath("$.message", is(INVALID_COURSE_STATUS.getMessage()))));
    }
}

 

 


반응형

+ Recent posts