class KotestExample : StringSpec({
"Strings" {
"length는 문자열의 길이를 반환해야 한다" {
"hello".length shouldBe 5
}
}
"중첩 하지 않아도 됨" {
"hello".length shouldBe 5
}
})
위 예시는 Kotest가 제공하는 10가지의 테스트 스타일 중 하나인 StringSpec의 사용 예시다.
Kotlin DSL을 적극 활용하여 문법이 매우 심플하다.
테스트 함수를 만들기 위해 public void
, fun
키워드를 사용하거나 @Test
어노테이션을 붙이지 않아도 되며,
가독성 떨어지고 매개변수 순서 헷갈리는 assertEquals(5, "hello".length)
assert 메서드 호출 대신
shouldBe 키워드를 사용하면 된다.
사용하기 위해 Dependency를 빌드 파일에 추가한다.
testImplementation 'io.kotest:kotest-runner-junit5:5.6.2'
testImplementation 'io.kotest:kotest-assertions-core:5.6.2'
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-runner-junit5-jvm</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-assertions-core-jvm</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
스타일 | 형태 |
---|---|
StringSpec | "" { } |
FunSpec | test("") { } |
ShouldSpec | should("") { } |
ExpectSpec | expect("") { } |
WordSpec | "" should { "" { } } |
FreeSpec | "" - { "" { } } |
DescribeSpec | describe("") { it("") { } } |
FeatureSpec | feature("") { scenario("") { } } |
BehaviorSpec | given("") { `when`("") { then("") { } } } |
AnnotationSpec | JUnit과 동일하게 사용 |
StringSpec
class MyTests : StringSpec({
"strings.length는 문자열의 길이를 반환해야 한다" {
"hello".length shouldBe 5
}
})
"" {
}
FunSpec
class MyTests : FunSpec({
test("String length는 문자열의 길이를 반환해야 한다") {
"sammy".length shouldBe 5
"".length shouldBe 0
}
})
test("") {
}
ShouldSpec
class MyTests : ShouldSpec({
should("문자열의 길이를 반환한다") {
"sammy".length shouldBe 5
"".length shouldBe 0
}
})
should("") {
}
ExpectSpec
class MyTests : ExpectSpec({
expect("테스트") {
// test here
}
})
expect("") {
}
WordSpec
class MyTests : WordSpec({
"String.length" should {
"문자열의 길이를 반환한다" {
"sammy".length shouldBe 5
"".length shouldBe 0
}
}
})
"" should {
"" {
}
}
FreeSpec
class MyTests : FreeSpec({
"String.length" - {
"문자열의 길이를 반환해야 한다" {
"sammy".length shouldBe 5
"".length shouldBe 0
}
}
})
"" - {
"" {
}
}
DescribeSpec
class MyTests : DescribeSpec({
describe("score") {
it("0으로 시작해야 한다") {
// test here
}
}
})
describe("") {
it("") {
}
}
FeatureSpec
class MyTests : FeatureSpec({
feature("한 캔의 콜라") {
scenario("흔들면 거품이 나야 한다") {
// test here
}
}
})
feature("") {
scenario("") {
}
}
BehaviorSpec
class MyTests : BehaviorSpec({
given("마법의 빗자루") {
`when`("앉으면") {
then("날 수 있어야 한다") {
// test code
}
}
`when`("던지면") {
then("다시 되돌아와야 한다") {
// test code
}
}
}
})
given("") {
`when`{
then {
}
}
}
AnnotationSpec
class AnnotationSpecExample : AnnotationSpec() {
@BeforeEach
fun beforeTest() {
println("Before each test")
}
@Test
fun test1() {
1 shouldBe 1
}
@Test
fun test2() {
3 shouldBe 3
}
}
JUnit과 동일
자주 사용하는 shouldBe와 shouldThrow만 소개한다.
나머지 Matcher들이 궁금하다면 참고
shouldBe
"hello".length shouldBe 5
shouldThrow
val exception = shouldThrow<IllegalAccessException> {
// IllegalAccessException 예외를 던질 것으로 예상되는 코드
}
exception.message shouldBe "예외 메시지"
Inspector는 컬렉션의 원소들을 한번에 테스트할 수 있게 해준다.
자주 사용하는 forAll만 소개한다.
나머지 Inspector들이 궁금하다면 참고
forAll
val names = listOf("sam", "smith", "sassy", "samuel")
names.forAll {
it.shouldStartWith("s")
}
class KotestExample : StringSpec({ // Spec
"Strings" { // Container
"length는 문자열의 길이를 반환해야 한다" { // TestCase
}
}
"중첩 하지 않아도 됨" { // TestCase
}
})
Spec ⊃ Container ⊃ TestCase의 구조로 되어있다.
Spec은 테스트 클래스(class KotestExample
)를 뜻한다.
Container는 중첩을 위해 한번 더 괄호로 묶은 부분("Strings" { }
)을 뜻한다
TestCase는 가장 안쪽의 괄호를 뜻한다.
이 계층 구조를 알아야 Isolation Modes와 Lifecycle Hooks를 이해할 수 있다.
모든 Container와 TestCase에 대해 각각의 인스턴스를 만들어 격리시킬지,
TestCase에 대해서만 각각의 인스턴스를 만들어 격리시킬지,
격리하지 않고 한 인스턴스 안에서 모든 Container와 TestCase를 실행시킬지 결정하는 부분이다.
SingleInstance
InstancePerTest
InstancePerLeaf
특정 Spec에서만 설정
class MyTestClass : WordSpec({
isolationMode = IsolationMode.SingleInstance
})
글로벌 설정
class ProjectConfig: AbstractProjectConfig() {
override val isolationMode = IsolationMode.InstancePerLeaf
}
JUnit으로 치면 @BeforeEach
@AfterEach
와 같은 것을 다루는 부분이다.
테스트 전/후의 어떤 시점에 특정 작업을 수행하도록 한다.
class TestSpec : WordSpec({
beforeTest {
println("Starting a test $it")
}
afterTest { (test, result) ->
println("Finished spec with result $result")
}
"this test" should {
"be alive" {
println("Johnny5 is alive!")
}
}
})
beforeContainer/afterContainer
beforeEach/afterEach
beforeTest/afterTest
beforeSpec/afterSpec
prepareSpec/afterSpec