13

I want to test class B:

class B : A {
    override fun init() {
        // do work here
    }
}

class A {
    protected fun init() { } // will be called by internal logic
}

and in Java there is no problem to call: b.init() within test method (test class is in the same package as test subject), but in Kotlin compiler complains:

Cannot access 'init': it is protected in 'B'

@Test
fun `checks init`() {
    val b = B()
    b.init()
    // assert work done
}

Why isn't it working? How can this be workaround (I want to avoid making method public)?

Kamil Seweryn
  • 2,072
  • 2
  • 17
  • 23
  • Possible duplicate of [What access modifier for testable helper methods?](http://stackoverflow.com/questions/30000983/what-access-modifier-for-testable-helper-methods) – JB Nizet Jan 15 '17 at 16:19
  • @JBNizet changing visibility on overridden method is with `internal` not possible and with `public` not really acceptable - especially since I can do it in Java – Kamil Seweryn Jan 15 '17 at 16:28

2 Answers2

12

protected in Java is not the same as in Kotlin.

In Java, everything in the same package can access a protected method. See In Java, difference between default, public, protected, and private

In Kotlin, protected means that you can only access it in the same class or any subclass of it. See Visibility Modifiers - Kotlin

The only possible way is to use the internal modifier and make the method visible to your tests in the same module.

Chris Jaynes
  • 2,868
  • 30
  • 29
D3xter
  • 6,165
  • 1
  • 15
  • 13
  • Class A is actually part of library, so cannot be changed and when I tried to put `internal` on overridden method it's not allowed – Kamil Seweryn Jan 15 '17 at 19:24
  • @KamilSeweryn if you think this info is relevant to your question (arguably, it is, since the context you provide basically invalidates this answer), you should probably add it to the question instead; comments are transient by definition on SO (yeah, I know I'm 6 years late to the party here :D) – spamove Feb 21 '23 at 19:43
10

Since Kotlin reduce visibility on protected (in compare to Java) by not allowing package access, the best option I could find is to workaround with reflection (since this is for testing I see no reason why not)

private fun invokeHiddenMethod(name: String) {
    val method = sut.javaClass.getDeclaredMethod(name)
    method.isAccessible = true
    method.invoke(testSubject)
}
Kamil Seweryn
  • 2,072
  • 2
  • 17
  • 23