'Spock and internal kotlin function

I am having trouble with using internal kotlin functions in my Spock tests. Here's short snippet of my spock test:

private def preconditions = new MonetaryPreconditions()
private def usdMonetary = new Monetary(BigDecimal.ZERO, Currency.USD)

def "should throw nothing because Monetaries currencies are same"(){
    when:
    preconditions.checkMonetariesCurrencies(usdMonetary , usdMonetary )
    then:
    noExceptionThrown()
}

and my MonetaryPreconditions class:

internal object MonetaryPreconditions {

  internal fun checkMonetariesCurrencies(monetary1: Monetary, monetary2: Monetary) {
    if (monetary1.currency != monetary2.currency) {
        throw CurrencyMismatchException(arrayOf(monetary1.currency, monetary2.currency), "Compared currencies does not match: " + monetary1.currency
                + " , " + monetary2.currency)
    }
  }

}

My test fails with a stacktrace:

groovy.lang.MissingMethodException: No signature of method: touk.recruitment.parkandrest.parkingmanagement.core.monetary.MonetaryPreconditions.checkMonetariesCurrencies() is applicable for argument types: (touk.recruitment.parkandrest.parkingmanagement.core.monetary.Monetary, touk.recruitment.parkandrest.parkingmanagement.core.monetary.Monetary) values: [touk.recruitment.parkandrest.parkingmanagement.core.monetary.Monetary@7c417213, ...]

The problem lies in internal visibility of my checkMonetariesCurrencies function. If I change it to public it works just fine, however I do want this to be module private. How can I achieve that with Spock?

Other information about my project:

  • Test class and MonetaryPreconditions have same package.
  • I am using Maven.
  • Test class and MonetaryPreconditions are of course in the same module.


Solution 1:[1]

I just ran into the same issue, and the workaround I used (suggested by an experienced coworker of mine) was to write a wrapper class in Kotlin (in the same package as the class under test (CUT); I placed the source code file in the test/kotlin folder) and just forward function calls to the CUT. I then used the wrapper class in my groovy unit test code.

Further, calling functions defined within an object in Kotlin from another programming language requires you to access the object's INSTANCE variable, e.g.

MonetaryPreconditions.INSTANCE.myfunction

In your case, the wrapper may look as follows:

package com.yourpackage

object MonetaryPreconditionsWrapper{
    fun checkMonetariesCurrencies(monetary1: Monetary, monetary2: Monetary){
        MonetaryPreconditions.checkMonetariesCurrencies(monetary1, monetary2)
    }
}

Now you can test the MonetaryPreconditions.checkMonetariesCurrencies function by simply calling the wrapper function from the groovy code as follows:

MonetaryPreconditionsWrapper.INSTANCE.checkMonetariesCurrencies(monetary1, monetary2)

Solution 2:[2]

Thanks you Giuseppe for your answer. However for me, Spock didn't see the wrapper as it thought it was a property of the test class and threw a groovy.lang.MissingPropertyException. I had add this to build.gradle:

compileTestGroovy.classpath += files(compileTestKotlin.destinationDir)

Taken from here: https://localcoder.org/test-classes-in-groovy-dont-see-test-classes-in-kotlin

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dmytro Lienko