Kotest 테스팅 스타일(Testing Styles)
테스트 스타일
Kotest에서는 다양한 테스트 스타일(Testing Styles)을 제공한다. 여기서는 Kotest에서 지원하는 테스트 스타일 10가지를 소개한다.
Testing Style | 영감을 받은 출처 |
---|---|
Fun Spec | ScalaTest |
String Spec | A Kotest original |
Should Spec | A Kotest original |
Describe Spec | Javascript frameworks and RSpec |
Behavior Spec | BDD frameworks |
Word Spec | ScalaTest |
Free Spec | ScalaTest |
Feature Spec | Cucumber |
Expect Spec | A Kotest original |
Annotation Spec | JUnit |
각각의 스타일은 특정한 문법을 따르며, 다양한 상황에 맞게 선택하여 사용할 수 있다. 각 테스트 스타일은 각각의 특성과 장단점을 가지고 있으며, 프로젝트의 요구 사항에 따라 적절한 스타일을 선택하여 사용할 수 있다.
아래는 각 테스트 스타일에 대해 설명하고 기본적인 사용법은 이중에 하나를 상속받아 작성되는데, 이를 예제 코드로 알아보도록 하겠다.
FunSpec
FunSpec
은 함수 기반의 테스트 스타일이다. 각 테스트 케이스를 함수로 작성하고, 테스트 본문을 함수 내에 작성한다.
FunSpec
을 사용하면 테스트를 설명하는 문자열 인수를 사용하여 test
라는 함수를 호출한 다음 테스트 자체를 람다로 호출하여 테스트를 만들 수 있다. 확실하지 않은 경우 이 스타일을 사용하는 것이 좋다.
아래는 FunSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
class FunSpecTest : FunSpec({
test("FunSpec 예제 - 덧셈 테스트") {
val result = 2 + 2
result shouldBe 4
}
})
일반적인 방법 외에도 xcontext
및 xtest
변형을 사용하여 테스트를 비활성화할 수 있다.
class MyTests : FunSpec({
context("this outer block is enabled") {
xtest("this test is disabled") {
// test here
}
}
xcontext("this block is disabled") {
test("disabled by inheritance from the parent") {
// test here
}
}
})
StringSpec
StringSpec
은 문자열 기반의 테스트 스타일이다. 자연어와 유사한 구문으로 테스트를 작성할 수 있다. 주로 각 테스트 케이스를 문자열로 작성하고, 테스트 본문을 중괄호 {}
내에 작성한다.
StringSpec
은 구문을 최소한으로 줄여준다. 테스트 코드에 문자열 뒤에 람다 식을 작성하기만 하면 된다.
아래는 StringSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
class StringSpecTest : StringSpec({
"StringSpec 예제 - 덧셈 테스트" {
val result = 2 + 2
result shouldBe 4
}
})
테스트에 구성 추가할 수도 있다.
class MyTests : StringSpec({
"strings.length should return size of string".config(enabled = false, invocations = 3) {
"hello".length shouldBe 5
}
})
ShouldSpec
ShouldSpec
은 FuncSpec
과 비슷하지만 테스트 대신 should
라는 키워드의 구문을 사용하여 작성한다. 테스트 케이스의 동작을 명세하는 데에 주로 사용된다.
아래는 ShouldSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.ShouldSpec
import io.kotest.matchers.shouldBe
class ShouldSpecTest : ShouldSpec({
should("ShouldSpec 예제 - 덧셈 테스트") {
val result = 2 + 2
result shouldBe 4
}
})
테스트는 하나 이상의 컨텍스트 블록에 중첩될 수도 있다:
class MyTests : ShouldSpec({
context("String.length") {
should("return the length of the string") {
"sammy".length shouldBe 5
"".length shouldBe 0
}
}
})
일반적인 방법 외에도 xcontext
및 xshould
변형을 사용하여 테스트를 비활성화할 수 있다.
class MyTests : ShouldSpec({
context("this outer block is enabled") {
xshould("this test is disabled") {
// test here
}
}
xcontext("this block is disabled") {
should("disabled by inheritance from the parent") {
// test here
}
}
})
DescribeSpec
DescribeSpec
테스트 스타일은 describe
/ it
키워드를 사용하기 때문에 Ruby 또는 자바스크립트 배경을 가진 사람들에게 익숙한 스타일을 제공한다.
describe
구문을 사용하여 테스트 케이스를 그룹화하고, 테스트는 하나 이상의 설명 블록에 중첩되어야 한다. 테스트 케이스를 설명하는 데에 주로 사용된다.
아래는 DescribeSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.shouldBe
class DescribeSpecTest : DescribeSpec({
describe("DescribeSpec 예제") {
it("덧셈 테스트") {
val result = 2 + 2
result shouldBe 4
}
}
})
일반적인 방법 외에도 xdescribe
및 xit
변형을 사용하여 테스트를 비활성화할 수 있다:
class MyTests : DescribeSpec({
describe("this outer block is enabled") {
xit("this test is disabled") {
// test here
}
}
xdescribe("this block is disabled") {
it("disabled by inheritance from the parent") {
// test here
}
}
})
BehaviorSpec
행위 기반의 테스트(BDD, Behavior Driven Development) 스타일의 작성 방법이다.
given
, when
, then
블록을 사용하여 테스트를 작성한다.
주요 기능이나 동작에 초점을 맞추어 테스트 케이스를 작성한다.
아래는 BehaviorSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.BehaviorSpec
import io.kotest.matchers.shouldBe
class BehaviorSpecTest : BehaviorSpec({
Given("BehaviorSpec 예제") {
When("덧셈 테스트") {
val result = 2 + 2
Then("2와 2를 더하면 4가 되어야 한다") {
result shouldBe 4
}
}
}
})
NOTE
when
은 Kotlin의 키워드이므로 백틱으로 묶어야 한다. 또는 백틱 사용이 마음에 들지 않는 경우 제목 대소문자 버전(예: Given
, When
, Then
)을 사용할 수 있다.
Given
, When
에 And
키워드를 사용하여 깊이를 더할 수도 있다:
class MyTests : BehaviorSpec({
given("a broomstick") {
and("a witch") {
`when`("The witch sits on it") {
and("she laughs hysterically") {
then("She should be able to fly") {
// test code
}
}
}
}
}
})
일반적인 방법 외에도 xgiven
, xwhen
및 xthen
변형을 사용하여 테스트를 비활성화할 수 있다:
class MyTests : BehaviorSpec({
xgiven("this is disabled") {
When("disabled by inheritance from the parent") {
then("disabled by inheritance from its grandparent") {
// disabled test
}
}
}
given("this is active") {
When("this is active too") {
xthen("this is disabled") {
// disabled test
}
}
}
})
WordSpec
WordSpec
은 문자열 기반의 테스트 스타일이다. 자연어와 유사한 구문을 사용하여 테스트를 작성한다.
should
키워드를 사용하여 컨텍스트 문자열 뒤에 테스트를 중첩하는 데 사용한다. 각 테스트 케이스를 문자열로 작성하고, 테스트 본문을 should
블록 내에 작성한다.
아래는 WordSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.WordSpec
import io.kotest.matchers.shouldBe
class WordSpecTest : WordSpec({
"WordSpec 예제 - 덧셈 테스트" should {
"2와 2를 더하면 4가 되어야 한다" {
val result = 2 + 2
result shouldBe 4
}
}
})
또한 다른 수준의 중첩을 추가할 수 있도록 허용할 때 when
키워드를 지원한다. when
은 Kotlin에서의 키워드이므로 백틱 또는 대문자 변형을 사용해야 한다는 점에 주의해야 한다.
class MyTests : WordSpec({
"Hello" When {
"asked for length" should {
"return 5" {
"Hello".length shouldBe 5
}
}
"appended to Bob" should {
"return Hello Bob" {
"Hello " + "Bob" shouldBe "Hello Bob"
}
}
}
})
FreeSpec
FreeSpec
은 자유로운 테스트 스타일이다. 테스트 케이스 간의 의존성을 줄이고, 독립적으로 테스트를 작성할 수 있다.
FreeSpec
을 사용하면 외부 테스트의 경우 키워드 -
(마이너스)를 사용하고 최종 테스트의 경우 테스트 이름만 사용하여 임의의 깊이 수준을 중첩할 수 있다:
아래는 FreeSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.shouldBe
class FreeSpecTest : FreeSpec({
"FreeSpec 예제 - 덧셈 테스트" - {
val result = 2 + 2
"2와 2를 더하면 4가 되어야 한다" {
result shouldBe 4
}
}
})
CAUTION
가장 안쪽 테스트는 테스트 이름 뒤에-
(마이너스) 키워드를 사용해서는 안 된다.
FeatureSpec
FeatureSpec
은 기능(Feature) 기반의 테스트 스타일이다. 각 테스트 케이스를 기능 또는 시나리오에 맞추어 작성한다.
FeatureSpec을 사용하면 기능 및 시나리오를 사용할 수 있으며, 이는 오이를 사용해 본 사람들에게 친숙할 것이다. 오이와 완전히 똑같지는 않지만 키워드는 스타일을 모방하고 있다.
아래는 FeatureSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.FeatureSpec
import io.kotest.matchers.shouldBe
class FeatureSpecTest : FeatureSpec({
feature("FeatureSpec 예제") {
scenario("덧셈 테스트") {
val result = 2 + 2
result shouldBe 4
}
}
})
일반적인 방법 외에도 xfeature 및 xscenario 변형을 사용하여 테스트를 비활성화할 수 있다:
class MyTests : FeatureSpec({
feature("this outer block is enabled") {
xscenario("this test is disabled") {
// test here
}
}
xfeature("this block is disabled") {
scenario("disabled by inheritance from the parent") {
// test here
}
}
})
ExpectSpec
테스트 스펙을 expect
구문을 사용하여 작성한다. 예상 결과를 명시하는 데에 주로 사용된다.
ExpectSpec
은 FunSpec
와 ShouldSpec
과 유사하지만 expect
키워드를 사용한다.
아래는 ExpectSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.ExpectSpec
import io.kotest.matchers.shouldBe
class ExpectSpecTest : ExpectSpec({
context("ExpectSpec 예제") {
expect("덧셈 테스트") {
val result = 2 + 2
2 + 2 shouldBe 4
}
}
})
테스트는 하나 이상의 컨텍스트 블록에 중첩될 수도 있다:
class MyTests : ExpectSpec({
context("a calculator") {
expect("simple addition") {
// test here
}
expect("integer overflow") {
// test here
}
}
})
일반적인 방법 외에도 xcontext
및 xexpect
변형을 사용하여 에스트를 비활성화할 수 있다.
class MyTests : ExpectSpec({
context("this outer block is enabled") {
xexpect("this test is disabled") {
// test here
}
}
xcontext("this block is disabled") {
expect("disabled by inheritance from the parent") {
// test here
}
}
})
AnnotationSpec
어노테이션 기반의 테스트 스타일이다. 특정 어노테이션을 사용하여 테스트를 작성한다.
JUnit에서 마이그레이션하는 경우 AnnotationSpec
은 JUnit 4/5와 같은 어노테이션을 사용하는 스펙이다. 스펙 클래스에 정의된 함수에 @Test
어노테이션을 추가하기만 하면 된다.
JUnit와 비슷하게 before tests/specs
과 after tests/specs
에 어노테이션을 추가할 수 있다.
@BeforeAll / @BeforeClass
@BeforeEach / @Before
@AfterAll / @AfterClass
@AfterEach / @After
테스트를 무시하려면 @Ignore
를 사용한다.
NOTE
이 스펙을 사용하면 일반적으로 임포트만 조정하면 되기 때문에 JUnit을 사용하는 것보다 큰 이점을 제공하지는 않지만 기존 테스트를 비교적 쉽게 마이그레이션할 수 있다.아래는 AnnotationSpec
에 대한 예제 코드이다:
package com.devkuma.kotest.tutorial.testingstyles
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.shouldBe
class AnnotationSpecExample : AnnotationSpec() {
@BeforeEach
fun beforeTest() {
println("Before each test")
}
@Test
fun test1() {
1 shouldBe 1
}
@Test
fun test2() {
3 shouldBe 3
}
}
테스트 구조화
Kotest는 테스트 구조화를 위해서 사용하는 함수는 context
블록을 사용하여 테스트 계층 또는 그룹으로 정의하여 테스트 케이스가 작성할 수 있다. 이렇게 함으로써 테스트를 논리적으로 분류하고 관련 테스트 케이스를 함께 관리할 수 있다.
예를 들어, 다음은 테스트 그룹을 사용하여 테스트를 구조화하는 예시이다:
import io.kotest.core.spec.style.FunSpec
class ContextTest : FunSpec({
context("Calculator tests") {
test("Addition") {
// Test logic for addition
}
test("Subtraction") {
// Test logic for subtraction
}
}
context("String tests") {
test("Length") {
// Test logic for string length
}
test("Concatenation") {
// Test logic for string concatenation
}
}
})
위의 예제에서는 context
블록을 사용하여 테스트 분류하여 나누고 있다.
context
블록은 FunSpec
, ShouldSpec
, ExpectSpec
에서만 사용할 수 있다.