1. Introduction

When writing test cases in Kotlin, it’s common to need to verify the type of an object. In this tutorial, we’ll explore how to assert that an object is an instance of a specific type using the Kotest testing framework. Kotest provides convenient assertion functions that allow us to perform these types of checks effortlessly. Let’s dive in and see how it’s done!

2. Asserting Instances Are Equal

To assert that an object is an instance of a specific type, we have two useful assertion functions available in Kotest: shouldBeInstanceOf() and shouldBeTypeOf(). We’ll work with a simple class hierarchy in our examples:

open class Vehicle(open val speed: Int, open val wheels: Int)

class Car(speed: Int) : Vehicle(speed, 4)
class Motorcycle(speed: Int) : Vehicle(speed, 2)

2.1. Using shouldBeInstanceOf()

The shouldBeInstanceOf() assertion function allows us to assert that an object is an instance of a specific type, including its subclasses:

test("Car should be instance of Vehicle") {
    val car = Car(10)
    car.shouldBeInstanceOf<Vehicle>()
}

In this example, we declare a variable car of type Car, which is an instance of the Vehicle class. Using shouldBeInstanceOf(), we assert that car is an instance of Vehicle, including its subclasses.

2.2. Using shouldBeTypeOf()

If we want to assert the exact type of an object, disregarding its subclasses, we can use the shouldBeTypeOf() assertion function:

test("A Car should be of type Car") {
    val vehicle: Vehicle = Car(10)

    vehicle.shouldBeTypeOf<Car>()
}

Our test will pass, as vehicle is indeed an instance of the class Car. shouldBeInstanceOf() and shouldBeTypeOf() are similar functions, with shouldBeTypeOf() being stricter. We can see the specificity of shouldBeTypeOf() when we try to check if car is of type Vehicle:

test("A Car should be of type Car") {
    val car: Vehicle = Car(10)

    car.shouldBeTypeOf<Car>()

    shouldFail {
        car.shouldBeTypeOf<Vehicle>()
    }
}

car is not exactly of type Vehicle because its class is Car, and thus, car.shouldBeTypeOf() fails.

3. Asserting Instances Are Different

In addition to asserting that instances are equal, we may also need to assert that instances are different or not of a specific type. Kotest provides two assertion functions for this purpose: *shouldNotBeInstanceOf() and shouldNotBeTypeOf(). These matchers are the exact opposite of shouldBeInstanceOf() and shouldBeTypeOf().* In this section, we’ll see them in action.

3.1. Using shouldNotBeInstanceOf()

The shouldNotBeInstanceOf() assertion function allows us to assert that an object is not an instance of a specific type, including its subclasses:

test("Motorcycle should not be instance of Car") {
    val vehicle: Vehicle = Motorcycle(15)

    vehicle.shouldNotBeInstanceOf<Car>()
}

In this test case, we ensure that our created Motorcycle is not an instance of Car. Let’s see what happens if we instead try to check if our Motorcycle is not a Vehicle:

test("Motorcycle should not be instance of Vehicle") {
    val motorcycle: Vehicle = Motorcycle(15)

    shouldFail {
        motorcycle.shouldNotBeInstanceOf<Vehicle>()
    }
}

As we can see, attempting to assert that a Motorcycle should not be a Vehicle fails since Motorcycle is a subclass of Vehicle.

3.2. Using shouldNotBeTypeOf()

And last but not least, we can look at the stricter version, shouldNotBeTypeOf(). This is for when we want to assert that an object is not of a specific type, disregarding its subclasses. Let’s see how to use the shouldNotBeTypeOf() assertion function:

test("A Motorcycle should not be of type Car") {
    val vehicle: Vehicle = Motorcycle(15)

    vehicle.shouldNotBeTypeOf<Car>()
}

This test passes, and the difference of the matchers becomes evident once again when we try to check that a Motorcycle should not be of type Vehicle:

test("A Motorcycle should not be of type Vehicle") {
    val motorcycle: Vehicle = Motorcycle(15)

    motorcycle.shouldNotBeTypeOf<Vehicle>() 
}

As expected, when checking for a specific type, our Motorcycle is indeed not of type Vehicle, even though it is a subclass of Vehicle. This test case passes, as opposed to motorcycle.shouldNotBeInstanceOf().

4. Conclusion

In this article, we explored how to assert the type of an object using the Kotest testing framework. We discussed four powerful assertion functions: shouldBeInstanceOf(), shouldNotBeInstanceOf(), shouldBeTypeOf(), and shouldNotBeTypeOf().

By using the shouldBeInstanceOf() assertion, we can verify that an object is an instance of a specific type, including its subclasses. Conversely, the shouldNotBeInstanceOf() assertion allows us to ensure that an object is not an instance of a particular type or any of its subclasses.

With the shouldBeTypeOf() assertion, we can precisely assert the exact type of an object, disregarding any subclasses. On the other hand, the shouldNotBeTypeOf() assertion lets us confirm that an object is not of a specific type.

These assertion functions provide a convenient way to validate the types of objects in our test cases, ensuring the correctness and reliability of our code. By leveraging Kotest’s expressive assertion capabilities, we can enhance the quality of our tests and increase confidence in our Kotlin projects. As always, the code used in this article is available over on GitHub.