Showing posts with label kotlin. Show all posts
Showing posts with label kotlin. Show all posts

2018-09-27

Testing Kotlin with Spock Part 3 - Interface default method

Kotlin allows you to put method implementation in an interface. The same mechanism can be found in Java interfaces as default methods (and also Groovy or Scala traits). Let's see the difference between the Kotlin and Java default methods in interface by testing it with Groovy and Spock.

What do we want to test?

We often have an interface for access object from the database. In domain, they might look similar to this KotlinOrderRepository:

interface KotlinOrderRepository {
    fun save(order: Order)

    fun find(orderId: OrderId): Order?

    fun get(orderId: OrderId): Order =
            find(orderId) ?: throw NotFound()
}

How to fake it with Groovy?

When we want to use such interface in tests, we can, of course, mock it. However, it is far better to fake repositories with a simple, in-memory implementation. Let's create FakeKotlinOrderRepository in Groovy:

class FakeKotlinOrderRepository implements KotlinOrderRepository {
    private Map<OrderId, Order> data = [:]

    @Override
    void save(Order order) {
        data[order.id] = order
    }

    @Override
    Order find(OrderId orderId) {
        return data[orderId]
    }
}

Unfortunately, this causes a compilation error

/testing-kotlin-in-spock/src/test/groovy/com/github/alien11689/testingkotlinwithspock/defaultmethod/FakeKotlinOrderRepository.groovy: 3: Can't have an abstract method in a non-abstract class. The class 'com.github.alien11689.testingkotlinwithspock.defaultmethod.FakeKotlinOrderRepository' must be declared abstract or the method 'com.github.alien11689.testingkotlinwithspock.defaultmethod.Order get(com.github.alien11689.testingkotlinwithspock.defaultmethod.OrderId)' must be implemented.
 @ line 3, column 1.
   class FakeKotlinOrderRepository implements KotlinOrderRepository {
   ^

1 error

The compiler doesn't see the implementation of the get method in the Kotlin interface. We have to use some magic to make it work in groovy.

Solution

To solve the problem, let's look into the generated classes:

$ ls build/classes/main/com/github/alien11689/testingkotlinwithspock/defaultmethod/
JavaOrderRepository.class
KotlinOrderRepository.class
KotlinOrderRepository$DefaultImpls.class
NotFound.class
Order.class
OrderId.class

The KotlinOrderRepository$DefaultImpls class is the one we're looking for as we can use it in Groovy to implement the missing operation.

class FakeKotlinOrderRepository implements KotlinOrderRepository {

    // ...

    Order get(OrderId orderId) {
        return KotlinOrderRepository.DefaultImpls.get(this, orderId)
    }
}

Now the code compiles and tests pass:

class KotlinRepositoryWithDefaultMethodTest extends Specification {
    OrderId orderId = new OrderId(UUID.randomUUID() as String)
    Order order = new Order(orderId, 'data')
    KotlinOrderRepository kotlinOrderRepository = new FakeKotlinOrderRepository()

    def 'should get order from kotlin repository'() {
        given:
            kotlinOrderRepository.save(order)
        expect:
            kotlinOrderRepository.get(orderId) == order
    }

    def 'should throw NotFound when order does not exist in kotlin repository'() {
        when:
            kotlinOrderRepository.get(orderId)
        then:
            thrown(NotFound)
    }
}

Is there the same problem with Java?

Let's have a quick look at how this works with Java interfaces. If we write a similar repository in Java:

public interface JavaOrderRepository {
    void save(Order order);

    Optional<Order> find(OrderId orderId);

    default Order get(OrderId orderId) {
        return find(orderId).orElseThrow(NotFound::new);
    }
}

and create a fake implementation in Groovy:

class FakeJavaOrderRepository implements JavaOrderRepository {
    private Map<OrderId, Order> data = [:]

    @Override
    void save(Order order) {
        data[order.id] = order
    }

    @Override
    Optional<Order> find(OrderId orderId) {
        return Optional.ofNullable(data[orderId])
    }
}

there is no compilation error and the tests pass:

class JavaRepositoryWithDefaultMethodTest extends Specification {
    OrderId orderId = new OrderId(UUID.randomUUID() as String)
    Order order = new Order(orderId, 'data')
    JavaOrderRepository javaOrderRepository = new FakeJavaOrderRepository()

    def 'should get order from java repository'() {
        given:
            javaOrderRepository.save(order)
        expect:
            javaOrderRepository.get(orderId) == order
    }

    def 'should throw NotFound when order does not exist in java repository'() {
        when:
            javaOrderRepository.get(orderId)
        then:
            thrown(NotFound)
    }
}

Groovy can implement Java interfaces with the default methods without any problems.

Show me the code

Code is available here.

2018-05-28

Testing Kotlin with Spock Part 2 - Enum with instance method

The enum class with instance method in Kotlin is quite similar to its Java version, but they are look a bit different in the bytecode. Let's see the difference by writing some tests using Spock.


What do we want to test?

Let's see the code that we want to test:
enum class EnumWithInstanceMethod {
    PLUS {
        override fun sign(): String = "+"
    },
    MINUS {
        override fun sign(): String = "-"
    };

    abstract fun sign(): String
}
Obviously, it can be written in a better way (e. g. using enum instance variable), but this example shows the case we want to test in the simplest way.


How to test it with Spock?

The simplest test (that does not work)

First, we can write the test like we would do it with a Java enum:
def "should use enum method like in java"() {
    expect:
        EnumWithInstanceMethod.MINUS.sign() == '-'
}
The test fails:
Condition failed with Exception:

EnumWithInstanceMethod.MINUS.sign() == '-'
                             |
                             groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS.sign() is applicable for argument types: () values: []
                             Possible solutions: sign(), sign(), is(java.lang.Object), find(), with(groovy.lang.Closure), find(groovy.lang.Closure)


    at com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.should use enum method like in java(EnumWithInstanceMethodTest.groovy:11)
Caused by: groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS.sign() is applicable for argument types: () values: []
Possible solutions: sign(), sign(), is(java.lang.Object), find(), with(groovy.lang.Closure), find(groovy.lang.Closure)
    ... 1 more
Interesting... Why is Groovy telling us that we are trying to call a static method? Maybe we are not using the enum instance but something else?. Let's create a test where we pass the enum instance to method:
static String consume(EnumWithInstanceMethod e) {
    return e.sign()
}

def "should pass enum as parameter"() {
    expect:
        consume(EnumWithInstanceMethod.MINUS) == '-'
}
Error message:
Condition failed with Exception:

consume(EnumWithInstanceMethod.MINUS) == '-'
|
groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.consume() is applicable for argument types: (java.lang.Class) values: [class com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS]
Possible solutions: consume(com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod)


    at com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.should pass enum as parameter(EnumWithInstanceMethodTest.groovy:29)
Caused by: groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.consume() is applicable for argument types: (java.lang.Class) values: [class com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS]
Possible solutions: consume(com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod)
    ... 1 more
Now we see that we passed the class com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS, not the enum instance.


But it works in Java...

Analogous code in JUnit works perfectly and the test passes:
@Test
public void shouldReturnSign() {
    assertEquals("-", EnumWithInstanceMethod.MINUS.sign());
}
Java can access Kotlin's instance method without problems, so maybe something is wrong with Groovy...
But the Java enum with instance method, e. g.
public enum EnumWithInstanceMethodInJava {
    PLUS {
        public String sign() {
            return "+";
        }
    },
    MINUS {
        public String sign() {
            return "-";
        }
    };

    public abstract String sign();
}
works correctly in the Spock test:
def "should use enum method"() {
    expect:
        EnumWithInstanceMethodInJava.MINUS.sign() == '-'
}


What's the difference?

We can spot the difference just by looking at the compiled classes:
$ tree build/classes/main/
build/classes/main/
└── com
    └── github
        └── alien11689
            └── testingkotlinwithspock
                ├── AdultValidator.class
                ├── EnumWithInstanceMethod.class
                ├── EnumWithInstanceMethodInJava$1.class
                ├── EnumWithInstanceMethodInJava$2.class
                ├── EnumWithInstanceMethodInJava.class
                ├── EnumWithInstanceMethod$MINUS.class
                ├── EnumWithInstanceMethod$PLUS.class
                ├── Error.class
                ├── Ok.class
                ├── ValidationStatus.class
                └── Validator.class
Java generates anonymous classes (EnumWithInstanceMethodInJava$1 and EnumWithInstanceMethodInJava$2) for the enum instances, but Kotlin names those classes after the enum instances names (EnumWithInstanceMethod$MINUS and EnumWithInstanceMethod$PLUS).
How does it tie into the problem with Groovy? Groovy does not need the .class when accessing class in code, so when we try to access EnumWithInstanceMethod.MINUS, Groovy converts it to EnumWithInstanceMethod.MINUS.class, not the instance of the enum. The same problem does not occur in Java code since there is no EnumWithInstanceMethodInJava$MINUS class.


Solution

Knowing the difference, we can solve the problem of accessing Kotlin's enum instance in our Groovy code.
The first solution is accessing the enum instance with valueOf method:
def "should use enum method working"() {
    expect:
        EnumWithInstanceMethod.valueOf('MINUS').sign() == '-'
}
The second way is to tell Groovy explicitly that we want to access the static field which is the instance of enum:
def "should use enum method"() {
    expect:
        EnumWithInstanceMethod.@MINUS.sign() == '-'
}
You can choose either solution depending on style of your code and your preferences.


Show me the code

Code is available here.

2018-03-13

Testing Kotlin with Spock Part 1 - Object

The object keyword in Kotlin creates singleton in a very convenient way. It can be used for example as a state of an operation. Spock Framework is one of the most expressive and readable test framework available in the Java ecosystem. Let's see how Kotlin object can be used in the Spock tests.

What do we want to test?

We have a single method validate in Validator interface which 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 - 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 - 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? It is because Error and Ok classes do not have overridden equals method. But why? We expects Kotlin objects (those created with object keyword, not plain object) to have it implemented correctly. What is more, it works correctly in Kotlin:

fun isOk(status:ValidationStatus) = status == Ok

Third - 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 comparisson, then we should access the class static property called 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 - alternative approach

We can also check the method result without 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

Code is available here;

2017-08-24

Using Kotlin extensions in Groovy

Extensions in Kotlin and Groovy

Kotlin and Groovy have mechanisms for extending existing classes without using inheritance or decorators. In both languages, the mechanisms are called extension methods. Their source code looks different, but generated bytecode is quite similar. Thanks to that, Groovy is able to use Kotlin extensions just like its own.

Why would I want to use such extensions in Groovy? The main reason is that I want to test my extensions using the best testing framework available for the JVM - Spock Framework.

Code is available here.

Extensions in Kotlin

There are many types of extensions in Kotlin. I decided to focus only on extension functions and properties.

As an example, I extend the java.lang.String class. First, I create an extension function skipFirst, which skips first N characters:


Next, I create an extension property answer, which is the Answer to the Ultimate Question of Life, the Universe, and Everything:


Both extensions are declared in package com.github.alien11689.extensions, in file called StringExtensions. However, the generated class in target directory is named StringExtensionsKt and this is the name that must be used when accessing from other languages. Specific class name can be forced by annotation @file:JvmName.

Using Kotlin extensions in Groovy

There are two ways for using extensions in Groovy that are supported by good IDEs. First, you can declare scope where the extensions are available by use method:


It is acceptable, but is not very convenient. The second and much better way is to use an extension module definition. The extension module is defined in file org.codehaus.groovy.runtime.ExtensionModule in directory src/main/resources/META-INF/services/. The same directory is monitored by ServiceLoader, but the file format is completely different:


The tests look much better now:

2015-11-14

Kotlin's extensions for each class

Extensions in Kotlin are very powerful mechanism. It allows for add any method to any of existing classes. Each instance has (as in Java) equals, toString and hashCode methods, but there is much more in Kotlin.

Example classes


Let's define some simple classes describing person: normal class and data class.

class PersonJaxb {
    var firstName: String? = null
    var lastName: String? = null
    var age: Int? = null
}

data class Person(val firstName: String, val lastName: String, val age: Int)

Normal class extensions


All instances have methods described below.

apply method


I often work with jaxb classes similar to PersonJaxb, which has not all arg constructor and all fields must be set via setters. Kotlin helps to deal with it via apply method. Target instance is provided as delagate to closure so we could define all fields values in it and returns this. The signature is T.apply(f: T.() -> Unit): T.

@Test
fun applyTest() {
    //when
    val person = PersonJaxb().apply {
        firstName = "John"
        lastName = "Smith"
        age = 20
    }

    //then
    assertEquals(20, person.age)
    assertEquals("John", person.firstName)
    assertEquals("Smith", person.lastName)
}

let method


Another extension is let method which is similar to map operation for collections. It has signature T.let(f: (T) -> R): R. this is passed as parameter to given closure/function.

@Test
fun letTest() {
    //when
    val fullName = Person("John", "Smith", 20).let {
        "${it.firstName} ${it.lastName}"
    }

    //then
    assertEquals("John Smith", fullName)
}

run method


run method looks like merge of apply and let methods: access to this is via delegate as in apply, but it also returns value as in let method. It has signature T.run(f: T.() -> R): R.

@Test
fun runTest() {
    //when
    val fullName = Person("John", "Smith", 20).run {
        "$firstName $lastName"
    }

    //then
    assertEquals("John Smith", fullName)
}

to method


Each instance has also defined to infix operator, which is used to create Pair. Pairs is helpful to create map entries. It has signature A.to(that: B): Pair<A, B>.

@Test
fun toTest() {
    //when
    val pair = Person("John", "Smith", 20) to 5

    //then
    assertEquals(Person("John", "Smith", 20), pair.first)
    assertEquals(5, pair.second)
}

Data class methods


Data class instances have also some other helpful methods (which are not extensions, but are generated for us).

componentX methods


Data class Person has three fields and it has component method generated for each of them: component1 for firstName, component2 for lastName and component3 for age.

@Test
fun componentsTest() {
    //when
    val p = Person("John", "Smith", 20)

    //then
    assertEquals("John", p.component1())
    assertEquals("Smith", p.component2())
    assertEquals(20, p.component3())
}

Why is it helpful? componentX methods are used in extracting (similar to Scala case classes extracting mechanism), e. g.:

@Test
fun extractingTest() {
    //when
    val (first, last, age) = Person("John", "Smith", 20)

    //then
    assertEquals(20, age)
    assertEquals("John", first)
    assertEquals("Smith", last)
}

copy method


copy method allows to create new instance based on current instance.

@Test
fun copyTest() {
    //when
    val person = Person("John", "Smith", 20).copy(lastName = "Kowalski", firstName = "Jan")

    //then
    assertEquals(Person("Jan", "Kowalski", 20), person)
}

Summary


Kotlin's extensions for each instances are very simple and help to solve many problems. The code written with these extensions is much more readable and concise than written in Java.

Sources are available here.

2015-10-11

Kotlin, Callable and ExecutorService

I've recently written about using Callable in Groovy, but how does it look like in kotlin?

Callable instance as separete class

First, let's create class which implements Callable interface:
class MyJob : Callable<Int> {
    override fun call() = 42
}

Now we could pass instance of this class to executorService:
fun callableAsClassInstance() =
    executorService.submit(MyJob()).get()

When we run it, as we expect, it returns 42. (Tests are written in groovy, not in kotlin).
def 'should submit callable as class instance from kotlin'() {
    expect:
        callableExample.callableAsClassInstance() == 42
}

Casting to Callable

If we create map with string "call" to closure or just closure and try to cast to Callable, we always obtain CastClassException:
fun callableAsMap() =
    executorService.submit(mapOf("call" to { 42 }) as Callable<Int>).get()

fun callableAsClosure() =
    executorService.submit({ 42 } as Callable<Int>).get()
def 'should submit callable as closure from kotlin'() {
    when:
        callableExample.callableAsClosure() == 42
    then:
        thrown(ClassCastException)
}

def 'should submit callable as map from kotlin'() {
    when:
        callableExample.callableAsMap() == 42
    then:
        thrown(ClassCastException)
}

It does not work as in groovy...

Pass instance method

So maybe passing an instance method which produces value will work?
private fun callMe() = 42

fun callableAsPassedFunction(): Int? {
    return executorService.submit(::callMe).get()
}

It does not even compile. Why? It moans that there is no submit method which could be called with such argument...

But, what interesting, if we create a value to which we assign closure and pass it to submit method then everything is ok and get returns 42.
private val callMe = { 42 }

fun callableAsPassedLocalFunction(): Int? {
    return executorService.submit(callMe).get()
}

Inline implementation

Of course, there is also an option to create Callable inline:
fun callableAsInlineImplementation() =
    executorService.submit(Callable<Int> { 42 }).get()

And this is IHMO the best and the most comfortable way to create Callable in kotlin, because its syntax is much nicer than in java or groovy.

Source code is available here.