Monday, October 12, 2020

Testing a Spring Boot Kotlin application with Kotest Example

 


How to use the SpringListener from Kotest to test Spring Boot applications, including some samples


Hello Kotliners!

In this article we'll see how to test Spring Boot apps using the Kotest Framework. We'll see some examples on how we test things using JUnit, and how to easily move to Kotest and enjoy it's features.

3 simple steps

  1. Add Kotest's Spring Extension to your build.gradle
  2. Transform your JUnit test into Kotest format (or create a new test from scratch)
  3. Add the SpringListener to your class

Add Kotest Spring Extension

On your build.gradle file we'll add the Spring Extension dependency as a testImplementation. I'm assuming you already have Kotest configured. If you don't, take a look at the docs on how to do it.


I like to keep the Spring Extension definition close to my Kotest definition

build.gradle

dependencies {
    // ... Your dependencies ... 

    // Kotest
    testImplementation("io.kotest:kotest-runner-junit5:{version}")
    testImplementation("io.kotest:kotest-extensions-spring:{version}")

}


Transform a JUnit test to a Kotest Spec

For this part we'll assume that we already have a component in our application:

@Component
class SimpleComponent {
    fun foo() = "Bar"
}

Yes yes, it's very simple and very dummy... But stay with me, we will go step by step!

We usually write a JUnit + Spring integrated test for this, validating that this bean works correctly.

There.are.many.guides that show us how to do it. Let's take this basic approach:

@RunWith(SpringRunner::class)
@SpringBootTest
class SimpleComponentTest  {

    @Autowired
    private lateinit var simpleComponent: SimpleComponent

    @Test
    fun fooShouldReturnBar(){
        Assert.assertEquals("Bar", simpleComponent.foo())
    }
}

Transform that test in a Kotest Spec

There are a lot of styles that can be used in Kotest, let's try with FunSpec.

Let's convert it exactly as is:

@RunWith(SpringRunner::class)
@SpringBootTest
class SimpleComponentTest : FunSpec() {

    @Autowired
    private lateinit var simpleComponent: SimpleComponent

    init {
        test("foo should return Bar") {
            simpleComponent.foo() shouldBe "Bar"
        }
    }
}

Aaaand our test crashes.

kotlin.UninitializedPropertyAccessException: lateinit property simpleComponent has not been initialized

It's ok, it's ok! We need to tell Kotest that this is a Spring Test!

Add the SpringListener to the class

To fix the above error, we need to add the SpringListener to our class' listeners:

@SpringBootTest
class SimpleComponentTest : FunSpec() {

    override fun listeners(): List<TestListener> {
        return listOf(SpringListener)
    }

    @Autowired
    private lateinit var simpleComponent: SimpleComponent

    init {
        test("foo should return Bar") {
            simpleComponent.foo() shouldBe "Bar"
        }
    }
}

Notice that we also removed the @RunWith(SpringRunner::class), as we are not running with JUnit anymore.

And voilà, it works!

Of course this is a very modest example. What about all the other configurations? Profiles, context configuration, TestConfiguration?

Don't worry! they'll work the same way as we're used to in JUnit. Annotating the constructor and such.

For example, messing with profiles:

@SpringBootTest(classes = [Components::class])
@ActiveProfiles("test-profile")
class ActiveProfileSpringTest : FunSpec() {

    override fun listeners() = listOf(SpringListener)

    @Value("\${test-foo}")
    lateinit var testFoo: String

    init {
        test("Should load active profile properties correctly") {
            testFoo shouldBe "bar"
        }
    }

}

test from Kotest test suite

And this is all we have for today! Go ahead and test your Spring Apps with Kotest! More information on this extension can be found at the docs

Doubts? Suggestions? Leave us a comment!


Reference :


Previous Post
Next Post

0 komentar: