Any way to force a static method to be generated in a kotlin class?

I'm trying to create a class in Kotiln which has a static method inside the bytecode so it works with JUnit's @Parameterized mechanism. Seems the bytecode doesn't get a static method - but the classes related class does.

e.g. this code…

import org.junit.* import org.junit.runners.AllTests import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters import java.util.List

[RunWith(javaClass<Parameterized>())]
public class MyTest(val id: String) {

  Test public fun checkQUnitTest(): Unit {
  println(“Testing $id”)
  }

  class object {
  Parameters public fun findValues(): List<String> {
           return arrayList(“a”, “b”)
  }
  }
}

generates this bytecode:

public final class tests.MyTest extends java.lang.Object implements jet.JetObject{   final java.lang.String id;   public static tests.MyTest$ClassObject$ $classobj;   public final void checkQUnitTest();   public final java.lang.String getId();   public tests.MyTest(java.lang.String);   public static {}; } public class tests.MyTest$ClassObject$ extends java.lang.Object implements jet.JetObject{   public final java.util.List findValues();   public tests.MyTest$ClassObject$(); }

I’m trying to get MyTest to have the static method findValues() on it. Anyone any idea how to make this happen? I realise it’ll make the bytecode a little bigger; but I’d like to create a static method that delegates to the class object’s methods. So this method appears by just delegating to the $classobj instance

``

  public static java.util.List findValues();

I can imagine others hitting this too in java interop (particularly things like junit)

Ah, the joys of JUnit requiring you to use static methods. James, why are you doing this to yourself? :-)

You can use package-level functions

I’m going to bump this because its at the top of google for ‘kotlin parameterized junit’

I didn’t try package level functions because I assumed the Parameterized JUnit driver wont look for them.

@cedricbeust thats a good point and it reveals an interesting quirk in my own thinking; I’m willing to push our project to use kotlin but I’m not willing to push off JUnit for TestNG --I guess that speaks to how good the intelliJ integration is, its a lot easier to update to kotlin than it would be for me to re-write our tests scripts to accept JUnit and TestNG.

That said, its worth mentioning, that in my case I ~solved this problem with pure kotlin.

class OPYLImporterGrammarFixture : CommonFixtureBase() {
    data class TestCase(val name : String, val document : String, val importantThing : Boolean)

    private val inputsByTestName = listOf(
        TestCase("single vertical input with minimal vals",
                    """inputs :
                    |  x1 :
                    |    lower : 1.23
                    |    upper : 2.34
                    """,
                   importantThing = true
             ),
             TestCase("single horizontal input with minimal vals",
                    """inputs :
                    |  x1 : { lower : 1.23, upper:2.34 }
                    """,
                    importantThing = false
            )
    );

    @Test fun when_parsing_document_should_parse_correctly(){

        for((name, document, important) in inputsByTestName){

            //setup
            val (parser, tokens, errorCount) = makeParserFor(document)

            //act
            val result = parser.document()

            //assert
            assertThat(errorCount()).describedAs("errorCount for $name").isEqualTo(0)
        }
    }
}

One problem is that the error messages on a system like this aren’t as nice since the tests context isn’t built into the stack like it is with a traditional test You could surround the body of the for loop in a try-catch, and add some context to the exception, but that would break some of intelliJs handling of comparison failures and etc. Still, in terms of making it look pretty, I think this is pretty spot-on.

This can now be mitigated with @JvmStatic

1 Like

As a much nicer alternative, use GitHub - Pragmatists/JUnitParams: Parameterised tests that don't suck
No more static methods / companion object code bloat.

A full example:

@RunWith(JUnitParamsRunner::class)
class ToSentenceCaseTest {

    @Test
    @Parameters
    fun test(input: String, expected: String) {
        assertThat(
                input.toSentenceCase()
        ).isEqualTo(
                expected
        )
    }

    fun parametersForTest() = arrayOf(
            arrayOf(""              , "" ),
            arrayOf("a"             , "A"),
            arrayOf("word"          , "Word"),
            arrayOf("multiple Words", "Multiple words")
    )

}
1 Like