Sling Academy
Home/Kotlin/Using `shouldBe` and `shouldThrow` in KotlinTest

Using `shouldBe` and `shouldThrow` in KotlinTest

Last updated: December 01, 2024

Testing is crucial in software development to ensure that applications behave as expected. KotlinTest is a powerful library available for Kotlin that allows developers to write tests efficiently and elegantly. Among the many features provided by KotlinTest, shouldBe and shouldThrow stand out for asserting conditions and expecting exceptions in your test cases.

Why Use KotlinTest?

KotlinTest brings a highly expressive way to write tests in Kotlin. It supports a variety of testing styles - from plain assertions to behavior-driven development (BDD) constructs. Its expressive DSL allows writing tests in a natural and concise manner.

Asserting with shouldBe

The shouldBe function is used for asserting that a particular value matches an expected value. It’s concise syntax and clear semantics make it easy to read and maintain.

Here's a simple example of using shouldBe:


import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe

class ExampleTest : StringSpec({
    "should return the correct sum" {
        val sum = 2 + 2
        sum shouldBe 4
    }
})

In this test, we're verifying that the result of adding two numbers is equal to 4. The shouldBe function checks if the value of sum matches 4, throwing an assertion error if it doesn't.

Exception Assertions with shouldThrow

Exception handling is also an important part of testing. The shouldThrow function enables you to assert that a specific block of code will throw an exception. This is particularly useful in scenarios where exceptions signify failure conditions or incorrect usage.

For example:


import io.kotest.core.spec.style.StringSpec
import io.kotest.assertions.throwables.shouldThrow

class ExceptionTest : StringSpec({
    "should throw an IllegalArgumentException if input is negative" {
        shouldThrow<IllegalArgumentException> {
            checkPositive(-1)
        }
    }

    fun checkPositive(number: Int) {
        if (number < 0) {
            throw IllegalArgumentException("Negative input not allowed.")
        }
    }
})

This example tests that an IllegalArgumentException is thrown for negative inputs, using shouldThrow. The function under test is checkPositive, which rightly throws an exception when passed -1.

Combining shouldBe and shouldThrow

You can harness the power of both shouldBe and shouldThrow together to assert conditions and exceptions in a comprehensive manner. This allows for highly robust test scenarios.

Consider combining both assertions in a single test suite:


import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.assertions.throwables.shouldThrow

class CombinedTest : StringSpec({
    "should calculate the absolute value" {
        val result = absolute(-5)
        result shouldBe 5
    }

    "should throw an exception for a specific condition" {
        shouldThrow<Exception> {
            causeError(true)
        }
    }

    fun absolute(number: Int): Int {
        return if (number >= 0) number else -number
    }

    fun causeError(shouldError: Boolean) {
        if (shouldError) {
            throw Exception("Triggered forceful error")
        }
    }
})

In this test suite, the first test case uses shouldBe to ensure that the absolute function returns the correct positive magnitude. The second example uses shouldThrow to assert that an exception is thrown by the causeError function when a specific condition is met.

Conclusion

KotlinTest’s shouldBe and shouldThrow functions are simple yet powerful tools that aid developers in writing concise and expressive tests. shouldBe helps validate correctness by comparing expected outputs, while shouldThrow enhances test robustness by handling expected failure scenarios. These functions not only make your code easier to read but also improve future maintainability.

Incorporating KotlinTest into your testing suite allows you to focus on testing complex business logic instead of boilerplate test code, accelerating the testing process while maintaining high quality and reliability in your codebase.

Next Article: Introduction to Mocking in Kotlin Testing

Previous Article: How to Test Data Classes in Kotlin

Series: Testing in Kotlin

Kotlin

You May Also Like

  • How to Use Modulo for Cyclic Arithmetic in Kotlin
  • Kotlin: Infinite Loop Detected in Code
  • Fixing Kotlin Error: Index Out of Bounds in List Access
  • Setting Up JDBC in a Kotlin Application
  • Creating a File Explorer App with Kotlin
  • How to Work with APIs in Kotlin
  • What is the `when` Expression in Kotlin?
  • Writing a Script to Rename Multiple Files Programmatically in Kotlin
  • Using Safe Calls (`?.`) to Avoid NullPointerExceptions in Kotlin
  • Chaining Safe Calls for Complex Operations in Kotlin
  • Using the Elvis Operator for Default Values in Kotlin
  • Combining Safe Calls and the Elvis Operator in Kotlin
  • When to Avoid the Null Assertion Operator (`!!`) in Kotlin
  • How to Check for Null Values with `if` Statements in Kotlin
  • Using `let` with Nullable Variables for Scoped Operations in Kotlin
  • Kotlin: How to Handle Nulls in Function Parameters
  • Returning Nullable Values from Functions in Kotlin
  • Safely Accessing Properties of Nullable Objects in Kotlin
  • How to Use `is` for Nullable Type Checking in Kotlin