Reputation: 2112
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)?
Upvotes: 14
Views: 16377
Reputation: 2519
There is one more option - create wrapper subclass and override the test target method with public visibility:
class FooTest {
@Test
fun testFoo() {
val foo = FooWrapper() // Instead of Foo
foo.protectedMethod()
}
private class FooWrapper : Foo() {
override public fun protectedMethod() {
super.protectedMethod()
}
}
}
This way, you wont need to modify the visibility of the original method, and will not use reflection. Also, the auxiliary wrapper class will remain invisible outside the test class.
Upvotes: 1
Reputation: 6435
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.
Upvotes: 13
Reputation: 2112
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)
}
Upvotes: 10