ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] Kotlin으로 REST API 만들기(7) - Kotlin으로 Controller 구현 및 단위 테스트(Junit5)
    Spring Boot/Kotlin으로 REST API 만들기 2022. 10. 30. 21:00
    반응형

    Kotlin으로 REST API 만들기(7) - Controller 구현 및 단위 테스트

    TodoController.kt를 구현한 후 JUnit5을 사용하여 단위 테스트를 작성하세요.

    1. TodoController.kt

    package com.example.springbootrestapi.web.controller
    
    import com.example.springbootrestapi.domain.TodoRequest
    import com.example.springbootrestapi.domain.TodoResponse
    import com.example.springbootrestapi.service.TodoService
    import org.slf4j.LoggerFactory
    import org.springframework.http.MediaType
    import org.springframework.web.bind.annotation.*
    import javax.servlet.http.HttpServletRequest
    import javax.servlet.http.HttpServletResponse
    
    @RestController
    class TodoController(
      val todoService: TodoService
    ) {
    
      private val log = LoggerFactory.getLogger(TodoController::class.java)
    
      /**
       * To-Do 목록 조회
       */
      @PostMapping(
        value = ["/api/todos"],
        consumes = [MediaType.APPLICATION_JSON_VALUE],
        produces = [MediaType.APPLICATION_JSON_VALUE]
      )
      fun getTodos(
        request: HttpServletRequest,
        response: HttpServletResponse,
        @RequestBody todoRequest: TodoRequest
      ): MutableList<TodoResponse> {
        log.info("todoRequest:[{}]", todoRequest.toString())
        return todoService.getTodos(todoRequest)
      }
    
      /**
       * To-Do 상세 조회
       */
      @GetMapping(
        value = ["/api/todo/{id}"],
        consumes = [MediaType.APPLICATION_JSON_VALUE],
        produces = [MediaType.APPLICATION_JSON_VALUE]
      )
      fun getTodoById(
        request: HttpServletRequest,
        response: HttpServletResponse,
        @PathVariable id: Long
      ): TodoResponse {
        log.info("id:[{}]", id)
        return todoService.getTodoById(id)
      }
    
      /**
       * To-Do 저장
       */
      @PostMapping(
        value = ["/api/todo"],
        consumes = [MediaType.APPLICATION_JSON_VALUE],
        produces = [MediaType.APPLICATION_JSON_VALUE]
      )
      fun insertTodo(
        request: HttpServletRequest,
        response: HttpServletResponse,
        @RequestBody todoRequest: TodoRequest
      ): TodoResponse {
        log.info("todoRequest:[{}]", todoRequest.toString())
        return todoService.insertTodo(todoRequest)
      }
    
      /**
       * To-Do 수정
       */
      @PutMapping(
        value = ["/api/todo"],
        consumes = [MediaType.APPLICATION_JSON_VALUE],
        produces = [MediaType.APPLICATION_JSON_VALUE]
      )
      fun updateTodo(
        request: HttpServletRequest,
        response: HttpServletResponse,
        @RequestBody todoRequest: TodoRequest
      ): TodoResponse {
        log.info("todoRequest:[{}]", todoRequest.toString())
        return todoService.updateTodo(todoRequest)
      }
    
      /**
       * To-Do 삭제
       */
      @DeleteMapping(
        value = ["/api/todo/{id}"],
        consumes = [MediaType.APPLICATION_JSON_VALUE],
        produces = [MediaType.APPLICATION_JSON_VALUE]
      )
      fun deleteTodo(
        request: HttpServletRequest,
        response: HttpServletResponse,
        @PathVariable id: Long
      ): TodoResponse {
        log.info("id:[{}]", id)
        return todoService.deleteTodoById(id)
      }
    }


    2. TestTodoController.kt

    package com.example.springbootrestapi.web.controller
    
    import com.example.springbootrestapi.domain.TodoRequest
    import com.example.springbootrestapi.mapper.TodoMapper
    import com.fasterxml.jackson.databind.ObjectMapper
    import org.hamcrest.CoreMatchers.`is`
    import org.hamcrest.CoreMatchers.equalTo
    import org.junit.jupiter.api.DisplayName
    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.http.MediaType
    import org.springframework.test.context.ActiveProfiles
    import org.springframework.test.web.servlet.MockMvc
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
    import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
    import org.springframework.transaction.annotation.Transactional
    
    @AutoConfigureMockMvc
    @SpringBootTest
    @ActiveProfiles("local")
    class TodoControllerTest {
    
      @Autowired
      lateinit var todoMapper: TodoMapper
    
      @Autowired
      lateinit var mockMvc: MockMvc
    
      @Autowired
      lateinit var objectMapper: ObjectMapper
    
      @Transactional
      @DisplayName("getTodos_To-Do 목록 조회")
      @Test
      fun testGetTodos() {
    
        // Given
        insertTodo("Title Junit Test Insert 01", "Description Junit Test Insert 01", false)
        insertTodo("Title Junit Test Insert 02", "Description Junit Test Insert 02", true)
        insertTodo("Title Junit Test Insert 03", "Description Junit Test Insert 03", false)
        insertTodo("Title Junit Test Insert 04", "Description Junit Test Insert 04", true)
        insertTodo("Title Junit Test Insert 05", "Description Junit Test Insert 05", false)
    
        val url = "/api/todos"
        val todoRequest = TodoRequest().apply {
          this.title = "Title Junit Test Insert"
          this.description = "Description Junit Test Insert"
          this.completed = true
        }
    
        // When
        val resultActions = mockMvc.perform(
          MockMvcRequestBuilders.post(url)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(todoRequest))
        )
    
        // Then
        resultActions
          .andExpect(status().isOk)
          .andExpect(content().contentType(MediaType.APPLICATION_JSON))
          .andExpect(jsonPath("$.length()", `is`(2)))
          .andDo(print())
      }
    
      @Transactional
      @DisplayName("getTodoById_To-Do 상세 조회")
      @Test
      fun testGetTodoById() {
    
        // Given
        val title = "Title Junit Test Insert"
        val description = "Description Junit Test Insert"
        val completed = false
        val insertId = insertTodo(title, description, completed)
        val url = "/api/todo/$insertId"
    
        // When
        val resultActions = mockMvc.perform(
          get(url)
            .contentType(MediaType.APPLICATION_JSON)
        )
    
        // Then
        resultActions
          .andExpect(status().isOk)
          .andExpect(content().contentType(MediaType.APPLICATION_JSON))
          .andExpect(jsonPath("$.title", equalTo(title)))
          .andExpect(jsonPath("$.description", equalTo(description)))
          .andExpect(jsonPath("$.completed", equalTo(completed)))
          .andDo(print())
      }
    
      @Transactional
      @DisplayName("insertTodo_To-Do 저장")
      @Test
      fun testInsertTodo() {
    
        // Given
        val url = "/api/todo"
        val todoRequest = TodoRequest().apply {
          this.title = "Title Junit Test Insert"
          this.description = "Description Junit Test Insert"
          this.completed = true
        }
    
        // When
        val resultActions = mockMvc.perform(
          post(url)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(todoRequest))
        )
    
        // Then
        resultActions
          .andExpect(status().isOk)
          .andExpect(content().contentType(MediaType.APPLICATION_JSON))
          .andExpect(jsonPath("$.title", equalTo(todoRequest.title)))
          .andExpect(jsonPath("$.description", equalTo(todoRequest.description)))
          .andExpect(jsonPath("$.completed", equalTo(todoRequest.completed)))
          .andDo(print())
      }
    
      @Transactional
      @DisplayName("updateTodo_To-Do 수정")
      @Test
      fun testUpdateTodo() {
    
        // Given
        val title = "Title Junit Test Insert"
        val description = "Description Junit Test Insert"
        val completed = false
        val insertId = insertTodo(title, description, completed)
        val url = "/api/todo"
        val todoRequest = TodoRequest().apply {
          this.id = insertId
          this.title = "Title Junit Test Insert"
          this.description = "Description Junit Test Insert"
          this.completed = true
        }
    
        // When
        val resultActions = mockMvc.perform(
          put(url)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(todoRequest))
        )
    
        // Then
        resultActions
          .andExpect(status().isOk)
          .andExpect(content().contentType(MediaType.APPLICATION_JSON))
          .andExpect(jsonPath("$.title", equalTo(todoRequest.title)))
          .andExpect(jsonPath("$.description", equalTo(todoRequest.description)))
          .andExpect(jsonPath("$.completed", equalTo(todoRequest.completed)))
          .andDo(print())
      }
    
      @Transactional
      @DisplayName("deleteTodo_To-Do 삭제")
      @Test
      fun testDeleteTodo() {
    
        // Given
        val title = "Title Junit Test Insert"
        val description = "Description Junit Test Insert"
        val completed = false
        val insertId = insertTodo(title, description, completed)
        val url = "/api/todo/$insertId"
    
        // When
        val resultActions = mockMvc.perform(
          delete(url)
            .contentType(MediaType.APPLICATION_JSON)
        )
    
        // Then
        resultActions
          .andExpect(status().isOk)
          .andDo(print())
      }
    
      fun insertTodo(
        title: String,
        description: String,
        completed: Boolean
      ): Long {
    
        var todoRequest = TodoRequest().apply {
          this.title = title
          this.description = description
          this.completed = completed
        }
    
        todoMapper.insertTodo(todoRequest)
    
        return todoRequest.id ?: 0
      }
    }


    3. 단위 테스트 확인
    좌측에 초록색 버튼(Run Test) 클릭 및 클래스 또는 메소드 내에서 우클릭하여 Run 클릭하여 단위 테스트가 정상적으로 동작하는지 확인하세요. (단축키 : Ctrl + Shift + F10)

     

    소스 코드는 Github Repository - https://github.com/tychejin1218/kotlin-springboot-rest-api.git (branch : section07) 를 참조하세요.

    GitHub에서 프로젝트 복사하기(Get from Version Control) - https://tychejin.tistory.com/325

    반응형

    댓글

Designed by Tistory.