How to test protected function

Yeah, looks inconvenient. Is the method how to properly test protected methods in final classes already found ?

You could use opt-in annotations and simply do a module-wide opt-in for the test module only.
E.g.:

@RequiresOptIn("This method is `internal` only for unit tests")
annotation class VisibleForUnitTests

class Foo {
  @VisibleForUnitTests
  internal fun bar() = TODO()
}

// Add compiler option "-opt-in=org.mylibrary.VisibleForUnitTests" in gradle config for the test module
// Then in tests
class FooUnitTests {
  @Test fun barTest() {
    Foo().bar() // Doesn't even need a `@OptIn(VisibleForUnitTests::class)` because of the compiler argument
  }
}
2 Likes

@franco why do you make yourself so complicated? one way to do is you can create a function that will return your protected abstract function then you can set that to @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE | NONE)

@kyay10 so you are actually creating your own @VisibleForTesting (which is only usable for Android if I get it right?) - nice idea!
But that wouldn’t work for protected functions, only for private ones, unless I am missing something?

1 Like

Well the point is that you change your protected and private functions to be internal and annotated with VisibleForTesting, which forces you everywhere else to not use those functions because you’ll read the opt-in message and realise that you shouldn’t opt-in to using those methods. Then in your gradle config you make the test sourceset automatically opt in to VisibleForTesting through the compiler option I mentioned, and hence your test code will automatically be able to access all VisibleForTesting methods without opting in manually.

@kyay10 > you change your protected and private functions to be internal

Well, as I said before, this of course works for private methods but NOT for protected.
But when you change protected to internal, you actually lose visibility which is not an option. protected method are meant to be used from outside, even outside your module.

So
 still no solution :frowning:

I haven’t done it myself but I assume https://mockk.io/ would work. You’d make a spy on your class, possibly abstract or an interface, do some verify declarations and It would magically (*bytecode manipulation) work like all things in Mockk–it’s quite a library.

Mockk supports mocks and spies with private methods as well.

1 Like