Search code examples
kotlinspock

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

  • 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)