KotlinTest로 Unit Test 작성하는 방법

코틀린에서 유닛테스트(Unit test)를 작성할 때 KotlinTest라는 라이브러리를 이용할 수 있습니다. 자바의 JUnit과 다르게 코틀린으로 작성되어 코틀린 코드를 테스트하는데 용이합니다. 이 글을 읽으시는 분은 아마도 JUnit을 사용해보셨을 것 같은데요. 이 글에서 빠르게 KotlinTest를 세팅하고 테스트하는 방법에 대해서 간단히 소개하겠습니다.

KotlinTest 프로젝트 설정

코틀린은 AndroidStudio나 IntelliJ에서 사용하실 것 같은데요. Gradle에서 KotlinTest 설정하려면 아래처럼 dependencies에 kotlintest를 추가해주셔야 합니다. KotlinTest에서 JUnit 기능을 이용하려면 아래처럼 test {} block을 만들고 그 안에 useJUnitPlatform() 를 선언해야 합니다.

test {
  useJUnitPlatform()
}

dependencies {
  testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.3.0'
}

Maven은 아래처럼 plugin과 dependency를 설정하시면 됩니다.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.1</version>
</plugin>
<dependency>
    <groupId>io.kotlintest</groupId>
    <artifactId>kotlintest-runner-junit5</artifactId>
    <version>3.3.0</version>
    <scope>test</scope>
</dependency>

설정을 모두 마쳤다면, 코드를 작성하면 됩니다. 저는 IntelliJ에서 그래들로 프로젝트를 만들었습니다. 저의 프로젝트의 구조는 다음과 같습니다. src/test/kotlin 아래에 코틀린 소스를 하나 생성하였습니다.

.
├── build.gradle
├── settings.gradle
└── src
    ├── main
    │   └── kotlin
    │       └── main.kt
    └── test
        └── kotlin
            └── BasicTest.kt

테스트 코드 작성

KotlinTest는 Spec이라는 이름으로 여러 테스트 스타일을 지원합니다. 가장 간단한 것은 String Spec입니다. StringSpec으로 기본적인 테스트 코드를 작성하겠습니다.

위의 프로젝트 구조에서 src/test/kotlin 경로 아래에 BasicTest.kt를 만들었습니다. 그리고 아래처럼 코드를 작성했습니다. 테스트하는 내용은 hello라는 문자열의 길이가 5개인지 체크하는 것입니다.

class BasicTest : StringSpec() {
    init {
        "strings.length should return size of string" {
            "hello".length shouldBe 5
        }
    }
}

테스트 코드를 작성하려면 먼저 클래스를 만들어야 합니다. BasicTest라는 이름의 클래스를 만들었습니다. 이 클래스는 StringSpec을 상속받아, StringSpec 스타일로 테스트 코드를 작성할 수 있었습니다. 테스트는 보통 init 아래에 작성합니다.

"strings.length should return size of string"는 단순히 테스트를 설명하는 description입니다. 이 테스트가 어떤 것을 테스트하는지 써주면 됩니다. 테스트를 이해하는데 쓰일 분, 테스트에 관여하지 않습니다. 이 문자열 다음으로 괄호 안에 실제 테스트할 코드를 구현하면 됩니다.

"hello".length shouldBe 5는 hello의 문자열 개수가 5개가 되어야 한다는 것을 말합니다. 5개가 아니라면 테스트가 실패합니다.

위 코드를 Java와 JUnit으로 다시 작성한다면, 아래와 비슷할 것입니다.

@Test
void checkStringLengthReturnSizeOfString() {
    assertEquals("hello".length(), 5);
}

테스트 스타일

지금까지 StringSpec이라는 스타일로 테스트 코드를 작성하는 방법을 알아보았습니다. 테스트 스타일을 변경하면 읽는 방식만 달라질 뿐 실제로 작성해야 하는 테스트 코드는 동일합니다. 개인이 선호하는 것을 사용하시면 됩니다. StringSpec은 가장 간단하기 때문에 특별히 원하는 것이 없다면 이것을 사용하는게 좋습니다.

StringSpec 외에 다른 Spec은 어떤 것들이 있는지 알아보겠습니다.

Fun Spec

Fuc Spec은 함수 형태로 테스트 코드를 작성하게 합니다. 함수 이름은 test로 해야 합니다. 스트링 인자는 단지 테스트를 설명하는 description입니다. 테스트 코드는 함수 안에 구현하면 됩니다.

class MyTests : FunSpec({
	test("String length should return the length of the string") {
		"sammy".length shouldBe 5
		"".length shouldBe 0
	}
})

Should Spec

ShouldSpec은 FunSpec과 비슷합니다. 대신 함수 이름이 should입니다. should를 description과 함께 읽을 때 어떤 테스트인지 이해하는데 도움이 될 수 있습니다.

class MyTests : ShouldSpec({
	should("return the length of the string") {
		"sammy".length shouldBe 5
		"".length shouldBe 0
	}
})

Word Spec

WordSpec도 should라는 키워드를 사용합니다. "String.length"는 Context string이라고 하는데 어떤 상황에서 테스트 하는 내용들이 있다는 것을 알려줄 때 쓸 수 있습니다. should 다음 { } block에 description과 테스트 코드를 작성할 수 있습니다.

class MyTests : WordSpec({
	"String.length" should {
		"return the length of the string" {
			"sammy".length shouldBe 5
			"".length shouldBe 0
		}
	}
})

Behavior Spec

BehaviorSpec은 BDD(Behavior-Driven Development) 스타일로 테스트 코드를 작성하게 합니다. 아래와 같이 given, when, then 키워드를 사용할 수 있습니다.

class MyTests : BehaviorSpec({
    given("a broomstick") {
        `when`("I sit on it") {
            then("I should be able to fly") {
                // test code
            }
        }
        `when`("I throw it away") {
            then("it should come back") {
                // test code
            }
        }
    }
})

Annotation Spec

AnnotationSpec은 Junit 스타일로 테스트 코트를 작성하게 합니다. 아래 코드는 Annotation을 붙이는 Junit과 비슷합니다.

class AnnotationSpecExample : AnnotationSpec() {

    @BeforeEach
    fun beforeTest() {
        println("Before each test")
    }

    @Test
    fun test1() {
        1 shouldBe 1
    }

    @Test
    fun test2() {
        3 shouldBe 3
    }
}

그외 Spec들..

그 외에 많은 Spec들이 있습니다. 테스트 코드를 작성하는 스타일일 뿐, 크게 달라지는 것은 없습니다. 선호하시는 것이 없다면 가장 간단한 StringSpec을 사용하세요.

다른 Spec들은 KotlinTest-GitHub에서 참고해주세요.

Matcher

Matcher는 테스트 코드를 작성하는데 도와주는 요소들입니다. 예를들어, 아래 코드에서 shouldBe는 동일함을 체크해주는 Matcher입니다.

"sammy".length shouldBe 5

하지만 shouldBe는 다양한 곳에서 사용할 수 있습니다. 아래 코드는 equal을 의미하기보다는 "hello world"의 lenght가 11이어야 함을 체크하고 있습니다.

"hello world" shouldBe haveLength(11)

이렇게 Matcher들은 어떤 변수나 상황을 Assert를 하는데 사용됩니다. 이런 Matcher들이 어떻게 사용되는지 알아보겠습니다.

String Matchers

String과 관련된 Matcher들은 다음과 같은 식으로 사용합니다.

"hello world" shouldBe haveLength(11)
"hello" should include("ll")
"hello" should endWith("lo")
"hello" should match("he...")
"hello".shouldBeLowerCase()

그 외에 많은 Matcher들은 KotlinTest에서 소개하고 있습니다.

Collection Matchers

String과 관련된 Matcher들은 다음과 같은 식으로 사용할 수 있습니다.

val list = emptyList<String>()
val list2 = listOf("aaa", "bbb", "ccc")
val map = mapOf<String, String>(Pair("aa", "11"))

list should beEmpty()
list2 shouldBe sorted<String>()
map should contain("aa", "11")
map should haveKey("aa")
map should haveValue("11")

정리

KotlinTest를 코틀린 프로젝트에 설정하는 방법부터, 코틀린 테스트를 작성하는 방법에 대해서 간단히 알아보았습니다. 자바의 JUnit과 다르다고 생각되는 부분은 매우 간단하게 테스트 코드를 작성할 수 있다는 것입니다. JUnit으로 작성하려면 Boilerplate 코드를 먼저 작성하고, 테스트마다 annotation도 붙이고 시작을 했었는데요. KotlinTest는 그 부분에서 자유로웠습니다. 자신의 개발환경에서 여러 테스트 툴을 쓸 수 있다면, 익숙하고 편안한 것을 사용하시면 좋을 것 같습니다.

참고

Loading script...
codechachaCopyright ©2019 codechacha