How can I use @Rule?

How can I use JUnit rules in Kotlin? The naive solution does not work:

Rule public val folder: TemporaryFolder = TemporaryFolder()

It fails with an error: org.junit.internal.runners.rules.ValidationError: The @Rule 'folder' must be public.

There seems to be no way to create an annotated field or am I missing something?

P.S. What exactly gets annotated here? The getter, the setter, the backing field, or all of them?

There already was a discussion about it and an issue (KT-3441).

What are the plans for this? I see that Kotlin doesn’t really need fields but compatibility with Java might. So this really is a compatibility issue. Especially, as the workaround from KT-3441is only possible because JUnit added support for annotating methods mit @Rule. That might not be the case for all java frameworks.

1 Like

Hi Dirk,

I worked around it by annotating a function instead of a property (and delegating to the property). e…g

 
val name = TestName()
Rule public fun name(): TestName = name

Cheers, Andrew

Thanks, Andrew. That's the workaround mentioned in the YouTrack issue.

I was hoping for a more succinct solution for this problem (as @Rules are very common in JUnit tests).

Hi Dirk,

Sorry, I didn’t notice it was the same solution.

I’m actually not too fussed about seamless support for annotations.

In fact, I’m hoping that Java idioms using annotations are not carried foward into Kotlin.

Kotlin has traits and higher-order functions that can usually replace annotations without some magic container.

Sorry, a bit of an off-topic rant there.

Here’s another work-around - using a RuleChain so you only have to annotate one method, not each rule.

 
class FooTest {
    val name = TestName()
    val expected = ExpectedException.none()

  Rule fun rules() = RuleChain.outerRule(name).around(expected)

  Test fun testRule() {
  println(name.getMethodName())
  }
}


Cheers,
Andrew

Im not a big fan of annotions either. It's just that JUnit requires them.

I looked into quite a few test frameworks and those code centric frameworks (JUnit, TestNG with AssertJ) seem to be a good fit for many projects. I’m not sure if Kotlin really requires a custom testing framework or whether a custom JUnit runner and a little helper functionality would suffice to smooth things over. There hasn’t been much activity going on in the Spek project in the last year or so. Anyway, those specification frameworks require a team that is willing to work on such a level and to keep descriptions up to date. That’s something I haven’t seen too often in large companies.

You can now achieve this with the @JvmField annotation, which instructs the compiler not to generate a getter or setter, and expose it as a field instead.

@Rule @JvmField val folder = TemporaryFolder()
4 Likes

Yes, this is now possible. Thanks for pointing it out.

1 Like

Thank you for providing the simplest answer here.

1 Like

Here is a solution

@Rule @JvmField
val folder: TemporaryFolder = TemporaryFolder()


@Before
fun setUp() {
    baseDirectory = folder.newFolder("temp_folder")
}

simply you can use use-site targets to do that.
You will have something like this

@get:Rule
val mainCoroutineRule = MainCoroutineRule()