{"id":13362,"date":"2018-03-13T23:15:00","date_gmt":"2018-03-13T22:15:00","guid":{"rendered":"http:\/\/touk.pl\/blog\/?guid=540fc840b9d16a8a81159dcd367c1800"},"modified":"2023-04-27T11:19:10","modified_gmt":"2023-04-27T09:19:10","slug":"testing-kotlin-with-spock-part-1-object","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2018\/03\/13\/testing-kotlin-with-spock-part-1-object\/","title":{"rendered":"Testing Kotlin with Spock Part 1 &#8211; Object"},"content":{"rendered":"<p>The <code>object<\/code> keyword in Kotlin creates singleton in a very convenient way. It can be used for example as a state of an operation. <a href=\"http:\/\/spockframework.org\/\">Spock Framework<\/a> is one of the most expressive and readable test frameworks available in the Java ecosystem. Let\u2019s see how Kotlin <code>object<\/code> can be used in the Spock tests.<\/p>\n<h2 id=\"what-do-we-want-to-test\">What do we want to test?<\/h2>\n<p>We have a single method <code>validate<\/code> in <code>Validator<\/code> interface which returns validation status: <code>Ok<\/code> or <code>Error<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\">sealed class ValidationStatus\r\nobject Ok : ValidationStatus()\r\nobject Error : ValidationStatus()\r\n\r\n\r\ninterface Validator<T> {\r\n    fun validate(value: T): ValidationStatus\r\n}<\/pre>\n<p>We also provide a simple implementation of this interface:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">class AdultValidator : Validator<Int> {\r\n    override fun validate(value: Int) = if (value >= 18) Ok else Error\r\n}<\/pre>\n<p>\u00a0<\/p>\n<h2 id=\"how-to-test-it-with-spock\">How to test it with Spock?<\/h2>\n<h3 id=\"first---silly-approach\"><span id=\"first-silly-approach\">First \u2013 silly approach<\/span><\/h3>\n<p>First, let\u2019s write a parameterized test for the validator:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\">AdultValidator sut = new AdultValidator()\r\n\r\ndef 'should validate age #age'() {\r\n    expect:\r\n        sut.validate(age) == result\r\n    where:\r\n        age | result\r\n        0   | Error\r\n        17  | Error\r\n        18  | Ok\r\n        19  | Ok\r\n}<\/pre>\n<p>\u00a0<\/p>\n<p>We expect it to pass, but it fails\u2026 <code>Error<\/code> and <code>Ok<\/code> are classes in the code above.<\/p>\n<h3 id=\"second---naive-approach\"><span id=\"second-naive-approach\">Second \u2013 naive approach<\/span><\/h3>\n<p>We need instances instead, so we modify the test a little:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\">def 'should validate age #age'() {\r\n    expect:\r\n        sut.validate(age) == result\r\n    where:\r\n        age | result\r\n        0   | new Error()\r\n        17  | new Error()\r\n        18  | new Ok()\r\n        19  | new Ok()\r\n}\r\n<\/pre>\n<p>\u00a0<\/p>\n<p>And again, this one fails as well. Why? It is because <code>Error<\/code> and <code>Ok<\/code> classes do not have overridden <code>equals<\/code> method. But why? We expects Kotlin objects (those created with <code>object<\/code> keyword, not plain object) to have it implemented correctly. What is more, it works correctly in Kotlin:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\">fun isOk(status:ValidationStatus) = status == Ok<\/pre>\n<h3 id=\"third---correct-approach\"><span id=\"third-correct-approach\">Third \u2013 correct approach<\/span><\/h3>\n<p>Let\u2019s look into the class file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">$ javap com\/github\/alien11689\/testingkotlinwithspock\/Ok.class\r\nCompiled from \"Validator.kt\"\r\npublic final class com.github.alien11689.testingkotlinwithspock.Ok extends com.github.alien11689.testingkotlinwithspock.ValidationStatus {\r\n  public static final com.github.alien11689.testingkotlinwithspock.Ok INSTANCE;\r\n  static {};\r\n}<\/pre>\n<p>If we want to access the real object that Kotlin uses in such comparisson, then we should access the class static property called <code>INSTANCE<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">def 'should validate age #age'() {\r\n    expect:\r\n        sut.validate(age) == result\r\n    where:\r\n        age | result\r\n        0   | Error.INSTANCE\r\n        17  | Error.INSTANCE\r\n        18  | Ok.INSTANCE\r\n        19  | Ok.INSTANCE\r\n}<\/pre>\n<p>Now the test passes.<\/p>\n<h3 id=\"fourth---alternative-approach\"><span id=\"fourth-alternative-approach\">Fourth \u2013 alternative approach<\/span><\/h3>\n<p>We can also check the method result without specific instance of the object class and use <code>instanceof<\/code> or <code>Class#isAssignableFrom<\/code> instead.<\/p>\n<p>Show me the code<\/p>\n<p>Code is available <a href=\"https:\/\/github.com\/alien11689\/testing-kotlin-with-spock\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"The object keyword in Kotlin creates singleton in a very convenient way. It can be used for example&hellip;\n","protected":false},"author":54,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[50,634,556,635,636,411,30],"class_list":{"0":"post-13362","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-groovy","8":"tag-interop","9":"tag-kotlin","10":"tag-object","11":"tag-signleton","12":"tag-spock","13":"tag-testing"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/13362","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/54"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=13362"}],"version-history":[{"count":12,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/13362\/revisions"}],"predecessor-version":[{"id":15664,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/13362\/revisions\/15664"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=13362"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=13362"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=13362"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}