강좌/Spring WebFlux & Coroutine

Lesson01. coRouter 로 웹 요청 받기

여름나라겨울이야기 2021. 12. 3. 19:41
728x90

 

 

1. coRouter 로 웹 요청 받기

1.1. Project 생성

  • 파일 정리
    • HELP.md 파일 삭제
    • src/main/resources/application.properties 의 확장자를 yml 로변경

1.2. Main 코드 작성

Hexagonal Architecture(Ports and Adapters Architecture) 를 내가 이해한데로 막 적용해 보자.

src/main/kotlin/com/haven/webcoroutine 아래 board 패키지 추가

1.2.1. Domain 구현

src/main/kotlin/com/haven/webcoroutine/board 아래 domain 패키지 추가

1.2.2. Entity 구현

src/main/kotlin/com/haven/webcoroutine/board/domain 아래 entity 패키지 추가

Board 클래스를 추가하고 아래와 같이 작성

Board.kt
1
2
3
4
5
6
7
8
9
10
package com.haven.webcoroutine.board.domain.entity

import java.time.Instant

data class Board(
    val id: Long,
    val title: String,
    val context: String,
    val createDateTime: Instant = Instant.now()
)

1.2.3. Router 구현

src/main/kotlin/com/haven/webcoroutine/board/ 아래 outbound 패키지 추가

src/main/kotlin/com/haven/webcoroutine/board/outbound 아래 web 패키지 추가

BoardRouter 클래스를 추가하고 아래와 같이 작성

BoardRouter.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.haven.webcoroutine.board.outbound.web

import com.haven.webcoroutine.board.domain.entity.Board
import kotlinx.coroutines.flow.asFlow
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.function.server.bodyAndAwait
import org.springframework.web.reactive.function.server.coRouter

@Configuration
class BoardRouter {
    // tag::test-data[]
    val boards = listOf(
        Board(1, "first", "one"),
        Board(2, "second", "two"),
        Board(3, "third", "three"),
        Board(4, "forth", "four"),
        Board(5, "fifth", "five"),
    )
    // end::test-data[]

    @Bean
    fun routeBoard() = coRouter {
        "boards".nest {
            GET("") {
                ServerResponse.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyAndAwait(
                        boards.asFlow()
                    )
            }
        }
    }
}

1.3. 브라우저를 통해 확인

1.4. Test 코드 작성

1.4.1. Test 편하게 편하게…​ 의존성 추가

  • kotest 라이브러리 추가

kotest 가 궁금하다면 남경호님의 글을 보자.
(P.S: Junit, Spock 따위…​)

build.gradle.kts 에 의존성 추가
1
2
3
4
5
6
    // Junit, Spock 대신 kotest 사용 추천
    // https://veluxer62.github.io/tutorials/getting-started-with-kotest/
    val kotestVersion = "5.0.0"
    testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")
    testImplementation("io.kotest:kotest-framework-datatest:$kotestVersion")
    testImplementation("io.kotest:kotest-property:$kotestVersion")

 

1.4.2. Test 구현

BoardRouterTest.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.haven.webcoroutine.board.outbound.web

import com.haven.webcoroutine.board.domain.entity.Board
import io.kotest.core.spec.IsolationMode
import io.kotest.core.spec.style.BehaviorSpec
import org.springframework.http.MediaType
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBodyList

internal class BoardRouterTest : BehaviorSpec() {
    init {
        isolationMode = IsolationMode.InstancePerLeaf

        val router = BoardRouter().routeBoard()

        val client = WebTestClient
            .bindToRouterFunction(router)
            .build()

        Given("Board") {
            When("List 를 요청하면") {
                val result = client.get()
                    .uri("/boards")
                    .exchange()

                Then("주세요") {
                    result.expectStatus().isOk
                        .expectHeader().contentType(MediaType.APPLICATION_JSON)
                        .expectBodyList<Board>().hasSize(5)
                }
            }
        }
    }
}

Test 를 실행해 보자.
웹 서버 그런 거 띄울 필요없다.
함수를 정의했고, 함수를 테스트하는데 굳이 웹 서버를 왜 띄워야 하는가?

 

반응형