https://kotest.io/docs/framework/testing-styles.html
Kotest는 10가지 다른 스타일의 테스트 레이아웃을 제공한다. 그중 일부는, 다른 테스트 프레임워크와 비슷한 구조로 만들어지기도 했다.
스타일 간에 기능적인 차이는 없다. 스레드, 태그 등 모두 동일한 유형의 구성을 허용하지만, 이는 단순히 테스트를 구성하는 방법에 대한 선호도의 문제이다.
코테스트를 사용하려면 테스트 스타일 중 하나를 확장하는 클래스 파일을 만들어야 한다. 그런 다음 원하는 Spec (추상)클래스를 상속받고 init {} 블록 안에서 테스트 케이스를 작성하면 된다.
테스트 스타일 | 유사한 테스트 프레임워크 |
---|---|
Fun Spec | ScalaTest |
String Spec | A Kotest original |
Should Spec | A Kotest original |
Describe Spec | Javascript frameworks과 RSpec |
Behavior Spec | BDD frameworks |
Word Spec | ScalaTest |
Free Spec | ScalaTest |
Feature Spec | Cucumber |
Expect Spec | A Kotest original |
Annotation Spec | JUnit |
FunSpec 테스트는 String으로 이름을 지정한다음 테스트 자체를 람다로 호출하여 테스트를 생성할 수 있다.
내용은 별다른 형식 없이 그냥 자유롭게 작성하고, 이름만 저런 식으로 지정해줄 수 있는 형식인 것 같다.
class MyTests : FunSpec({
test("String length should return the length of the string") {
"sammy".length shouldBe 5
"".length shouldBe 0
}
})
Fun Spec과 똑같은 방식이지만, test()
로 묶어줄 필요 없이 바로 string과 람다를 써서 작성하는 Spec이다.
class MyTests : StringSpec({
"strings.length should return size of string" {
"hello".length shouldBe 5
}
})
추가설정은 이런 식으로 할 수 있다.
class MyTests : StringSpec({
"strings.length should return size of string".config(enabled = false, invocations = 3) {
"hello".length shouldBe 5
}
})
ShouldSpec은 funSpec에서 test
만 should
로 바뀐 것이다.
class MyTests : ShouldSpec({
should("return the length of the string") {
"sammy".length shouldBe 5
"".length shouldBe 0
}
})
Describe Spec은 DCI 패턴으로 테스트코드를 작성할 수 있는 Spec이다.
describe에는 도메인 혹은 함수명, 어떻게 되는지를 각각 적으면 된다.
class MyTests : DescribeSpec({
describe("score") {
it("start as zero") {
// test here
}
describe("with a strike") {
it("adds ten") {
// test here
}
it("carries strike to the next frame") {
// test here
}
}
describe("for the opposite team") {
it("Should negate one score") {
// test here
}
}
}
})
Docs에 예시는 위와 같이 되어있지만, Describe Spec으로는 보통 중간에 context를 껴서 이런식으로 작성하는 경우가 많다.
JUnit5로 DCI 패턴을 쓰려면 이렇게 해야하는데, Kotest를 쓰면 중첩테스트가 되니까 그냥 할 수 있다.
describe("PASSWORD_EXP") {
context("영어 대소문자, 영어, 특수문자가 포함된 8-30자의 문자열이 주어지면"){
val string = "Password!1"
it("참이 반환된다") {
Pattern.matches(RegexUtil.PASSWORD_EXP, string) shouldBe true
}
}
}
우리가 보통 아는 given
, when
, then
패턴이다.
하지만 when이 Kotlin의 예약어이기 때문에 Behavior Spec을 사용할떄 backtick(`)으로 감싸서 사용해야한다. 그게 마음에 들지 않는 경우 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
}
}
}
})
WordSpec은 context 문자열 뒤에 테스트를 키워드 should를 사용하여 테스트를 작성한다.
class MyTests : WordSpec({
"String.length" should {
"return the length of the string" {
"sammy".length shouldBe 5
"".length shouldBe 0
}
}
})
또한 다른 수준의 중첩을 추가할 수 있는 When 키워드를 지원한다.
여기에서도 역시 when은 backtick(`) 또는 대문자 변형을 사용해야 한다.
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"
}
}
}
})
Free Spec에서는 키워드 -
(빼기)를 사용하여 임의의 깊이 수준을 중첩할 수 있다.
class MyTests : FreeSpec({
"String.length" - {
"should return the length of the string" {
"sammy".length shouldBe 5
"".length shouldBe 0
}
}
"containers can be nested as deep as you want" - {
"and so we nest another container" - {
"yet another container" - {
"finally a real test" {
1 + 1 shouldBe 2
}
}
}
}
})
FeatureSpec은 feature, scenario를 사용한다. (cucumber와 비슷하다)
class MyTests : FeatureSpec({
feature("the can of coke") {
scenario("should be fizzy when I shake it") {
// test here
}
scenario("and should be tasty") {
// test here
}
}
})
ExpectSpec은 FunSpec, ShouldSpec과 비슷하며, expect
키워드를 사용한다.
class MyTests : ExpectSpec({
expect("my test") {
// test here
}
})
context 블록에 중첩하여 작성할 수도 있다.
class MyTests : ExpectSpec({
context("a calculator") {
expect("simple addition") {
// test here
}
expect("integer overflow") {
// test here
}
}
})
JUnit과 동일한 방식이다. 별다른 이점은 없지만, 기존 형식을 그대로 가져올 수 있어 더 빠른 마이그레이션이 가능하다.
class AnnotationSpecExample : AnnotationSpec () {
@BeforeEach fun beforeTest () {
println ( " 각 테스트 전 " )
}
@Test fun test1 () {
1 shouldBe 1
}
@Test fun test2 () {
3 shouldBe 3
}
}