Testing Kotlin With Spock (Part 1): Object
Like using Spock for your tests? See how you can use it to test Kotlin code. This introduction focuses on making tests work with Kotlin's object keyword.
Join the DZone community and get the full member experience.
Join For FreeThe object
keyword in Kotlin creates a singleton in a very convenient way. It can be used, for example, as a state of an operation. Spock is one of the most expressive and readable test frameworks available in the Java ecosystem. Let's see how Kotlin's object
can be used in Spock tests.
What Do We Want to Test?
We have a single method, validate
, in our Validator
interface that returns validation status: Ok
or Error
.
sealed class ValidationStatus
object Ok : ValidationStatus()
object Error : ValidationStatus()
interface Validator<T> {
fun validate(value: T): ValidationStatus
}
We also provide a simple implementation of this interface:
class AdultValidator : Validator<Int> {
override fun validate(value: Int) = if (value >= 18) Ok else Error
}
How to Test it With Spock?
First: The Silly Approach
First, let's write a parameterized test for the validator:
AdultValidator sut = new AdultValidator()
def 'should validate age #age'() {
expect:
sut.validate(age) == result
where:
age | result
0 | Error
17 | Error
18 | Ok
19 | Ok
}
We expect it to pass, but it fails... Error
and Ok
are classes in the code above.
Second: The Naive Approach
We need instances instead, so we modify the test a little:
def 'should validate age #age'() {
expect:
sut.validate(age) == result
where:
age | result
0 | new Error()
17 | new Error()
18 | new Ok()
19 | new Ok()
}
And again, this one fails as well. Why? Because the Error
and Ok
classes do not have overridden equals
methods. But why? We expect Kotlin objects (those created with the object
keyword, not plain objects) to have it implemented correctly. What is more, it works correctly in Kotlin:
fun isOk(status:ValidationStatus) = status == Ok
Third: The Correct Approach
Let's look into the class file:
$ javap com/github/alien11689/testingkotlinwithspock/Ok.class
Compiled from "Validator.kt"
public final class com.github.alien11689.testingkotlinwithspock.Ok extends com.github.alien11689.testingkotlinwithspock.ValidationStatus {
public static final com.github.alien11689.testingkotlinwithspock.Ok INSTANCE;
static {};
}
If we want to access the real object that Kotlin uses in such a comparison, then we should access the class static property INSTANCE
:
def 'should validate age #age'() {
expect:
sut.validate(age) == result
where:
age | result
0 | Error.INSTANCE
17 | Error.INSTANCE
18 | Ok.INSTANCE
19 | Ok.INSTANCE
}
Now the test passes.
Fourth: An Alternative Approach
We can also check the method result without a specific instance of the object class and use instanceof
or Class#isAssignableFrom
instead.
def 'should validate age #age'() {
when:
ValidationStatus result = sut.validate(age)
then:
result.class.isAssignableFrom(expected)
where:
age | expected
0 | Error
17 | Error
18 | Ok
19 | Ok
}
Show me the Code
The code is available here.
Published at DZone with permission of Dominik Przybysz. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments