Ключевое слово object
в Kotlin создает синглтон очень удобным способом. Это может использоваться, например, как состояние операции. Spock Framework — одна из наиболее выразительных и удобочитаемых сред тестирования, доступных в экосистеме Java. Давайте посмотрим, как object
Kotlin может быть использован в тестах Спока.
Что мы хотим проверить?
У нас есть единственный метод validate
в интерфейсе Validator
который возвращает статус проверки: Ok
или Error
.
1
2
3
4
5
6
7
|
sealed class ValidationStatus object Ok : ValidationStatus() object Error : ValidationStatus() interface Validator<T> { fun validate(value: T): ValidationStatus } |
Мы также предоставляем простую реализацию этого интерфейса:
1
2
3
|
class AdultValidator : Validator<Int> { override fun validate(value: Int) = if (value >= 18 ) Ok else Error } |
Как это проверить со Споком?
Первый — глупый подход
Сначала напишем параметризованный тест для валидатора:
01
02
03
04
05
06
07
08
09
10
11
12
|
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 } |
Мы ожидаем, что это пройдет, но это не удастся … Error
и Ok
— это классы в коде выше.
Второе — наивный подход
Вместо этого нам нужны экземпляры, поэтому мы немного изменим тест:
01
02
03
04
05
06
07
08
09
10
|
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() } |
И снова, этот тоже не работает. Почему? Это потому, что классы Error
и Ok
не имеют переопределенного метода equals
. Но почему? Мы ожидаем, что объекты Kotlin (созданные с помощью ключевого слова object
, а не plain object) будут реализованы правильно. Более того, он правильно работает в Kotlin:
1
|
fun isOk(status:ValidationStatus) = status == Ok |
В-третьих — правильный подход
Давайте посмотрим на файл класса:
1
2
3
4
5
6
|
$ 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 {}; } |
Если мы хотим получить доступ к реальному объекту, который Kotlin использует в таком сравнении, тогда мы должны получить доступ к статическому свойству класса INSTANCE
:
01
02
03
04
05
06
07
08
09
10
|
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 } |
Сейчас тест проходит.
Четвертый — альтернативный подход
Мы также можем проверить результат метода без конкретного экземпляра класса объекта и использовать вместо него instanceof
или Class#isAssignableFrom
.
01
02
03
04
05
06
07
08
09
10
11
12
|
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 } |
Покажи мне код
Код доступен здесь ;
Смотрите оригинальную статью здесь: Тестирование Kotlin с помощью Спока. Часть 1. Объект
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |