스프링 프레임워크/kotlin

Java/Spring -> Kotlin/Spring 변환 - 3

blogger903 2024. 7. 28. 20:59
728x90

환경
IDE: intellij
SpringBootVersion: 2.7.18
Gradle: 8.5
Java: 17

 

해당 포스팅은
인프런 "코틀린 문법부터 실무까지 (자바 to 코틀린 실무)" 을 따라하면서 Java/Spring 프로젝트를 Kotlin/Spring 프로젝트로
점진적인으로 변환하는 내용을 담고 있습니다

다루는 내용

  • JUnit5 -> Kotest

Kotest에서는 10가지의 다양한 스타일의 테스트 레이아웃을 제공합니다

테스트 레이아웃도 테스트 작성시 고민하는 요소인데 그런것도 레이아웃으로 제공해줍니다

참고: https://kotest.io/docs/framework/testing-styles.html

 

enum-when처럼 테스트 레이아웃도 짜잘하지만 개발자들 입장에서는 쓸데없는 고민하지 않게되는 행복코딩으로 거듭날 수 있는 이유들때문에 Kotlin은 상당히 매력적입니다

라이브러리 추가 방법

    var kotestVersion = "5.8.0"
    testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion")

util class Junit5 -> Kotest 변환

기존 JUnit 테스트 코드

class DateTimeUtilsTest {
    @Test
    void getLocalDateTimeStringTest() {
        String result = DateTimeUtils.getLocalDateTimeString(
                LocalDateTime.of(2023, 12, 21, 10, 10)
        );

        assertEquals("2023-12-21 탄생", result);
    }
}

Convert to Java file to kotlin file 실행해줍니다
JUnit기반 테스트가 동작하도록 코드를 수정해줍니다

internal class DateTimeUtilsTest {

    @Test
    fun localDateTimeStringTest() {
            val result = getLocalDateTimeString(
                LocalDateTime.of(2023, 12, 21, 10, 10)
            )
            Assertions.assertEquals("2023-12-21 탄생", result)
        }
}

kotest StringSpec으로 변환합니다

internal class DateTimeUtilsTest : StringSpec ({
    "DateTimeUtil 출력 검증" {
        val result = getLocalDateTimeString(
            LocalDateTime.of(2023, 12, 21, 10, 10)
        )
        Assertions.assertEquals("2023-12-21 탄생", result)
    }
})

테스트 코드를 kotest 테스트 레이아웃으로 해도 run icon이 보이지 않는 경우

plugin에서 kotest를 설치해주세요

kotest plugin 설치후 run icon이 보입니다

kotest plugin을 설치하게되면
kotlin파일에서 cmd + shift + t 눌러서 테스트 코드 자동 생성 기능이 있습니다

infix function을 이용한 방법으로 assertion을 수정합니다

internal class DateTimeUtilsTest : StringSpec ({
    "DateTimeUtil 출력 검증" {
        val result = getLocalDateTimeString(
            LocalDateTime.of(2023, 12, 21, 10, 10)
        )
        result shouldBe "2023-12-21 탄생"
    }
})

BehaviorSpec으로 Service 테스트코드 구현

mockk()는 타입에 맞는 mock객체를 만들어줍니다.
typescript로 개발할때 jest를 사용해보신 분들은 jest.fn()와 유사한 경험을 할 수 있습니다

테스트케이스 작성할때 정상 동작 검증, 예외케이스 검증, 실패 검증을 나눠서 합니다
이럴때 Given데이터는 대부분 재사용할 수 있습니다

그러나 jest로 개발할때나 JUnit을 사용할때는 중복코드를 작성했었습니다. 테스트 코드의 Given부분은 함수로 빼지 않았어요.
오히려 함수로 빼면 테스트 코드를 파악하기가 어려웠습니다. 개인차가 있을 수 있습니다.

그런데 Kotest BehaviorSpec을 사용하면 공통 코드를 중복으로 작성하지 않아도 충분히 가독성이 있게 테스트 케이스를 작성할 수 있었습니다.


class PrinceMakerServiceKTest : BehaviorSpec({
    var princeRepository: PrinceRepository = mockk()
    var woundedPrinceRepository: WoundedPrinceRepository = mockk()

    var princeMakerService: PrinceMakerService = PrinceMakerService(princeRepository, woundedPrinceRepository)

    Given("프린스 생성 요청이 들어왔을 때") {
        var request = CreatePrince.Request(
            princeLevel = JUNIOR_PRINCE,
            skillType = INTELLECTUAL,
            experienceYears = 3,
            princeId = "princeId",
            name = "name",
            age = 38
        )

        var juniorPrince = PrinceMock.createPrince(
            JUNIOR_PRINCE, INTELLECTUAL, PrinceMakerConstant.MAX_JUNIOR_EXPERIENCE_YEARS, "princeId"
        )

        every { princeRepository.save(any()) } returns juniorPrince

        When("id가 중복되지 않고 정상 요청인 경우") {

            every {
                princeRepository.findByPrinceId(any())
            } returns Optional.empty()

            Then("정상 응답을 합니다") {
                val response = princeMakerService.createPrince(request)
                response.princeLevel shouldBe JUNIOR_PRINCE
                response.skillType shouldBe INTELLECTUAL
                response.experienceYears shouldBe 3
            }
        }

        When("id가 중복되고 정상 요청인 경우") {

            every {
                princeRepository.findByPrinceId(any())
            } returns Optional.of(juniorPrince)

            val ex = shouldThrow<PrinceMakerException> {
                princeMakerService.createPrince(request)
            }

            Then("익셉션 발생합니다") {
                ex.princeMakerErrorCode shouldBe DUPLICATED_PRINCE_ID
            }
        }
    }
})

테스트 결과도 Given, When, Then으로 중첩되서 보여지기 때문에 가독성이 좋습니다