How can I open class only to test class?
Asked Answered
W

2

7

I'm mainly a Java developer and wonder about structure when writing unit test in kotlin,

Assuming there's no package-private in kotlin

private to restrict visibility to the file

internal to restrict visibility to the module

How can I open class only to test class ?

Must I write test inside kotlin class or open class to all module (internal)?

What's the kotlin way to open method for unit test only?

EDIT

Found similar question/request in kotlin discuss by @bentolor:

How am I supposed to do unit / whitebox testing properly? I want to write test code which tests class-internal functionality which I do not want to expose to other classes except my test class at all.

The package protected visibility is an excellent way to achieve this. Whereas Kotlin now requires me to make these methods effectively public and litter the visible API of my component all-over the project be able to test them.

In my view internal is more or less public as it has a much larger scope. Most projects have sth. around 1 - 5 “modules” in the Kotlin sense.

Really strongly asking/advocating for package-local visibility here.

Weatherbeaten answered 3/12, 2019 at 13:36 Comment(5)
I don't have an answer to your question, but to me the discussion you linked is not fully correct. You may want to open your class for testing only (e.g. to stub it in unit tests for other classes) – which I guess is your question, and I'd be interested in a possible solution, too – however if you want to unit test an internal method you should do it by calling public methods of that class; I don't think it's correct to "open" a method that's meant to be private just so you can unit test itTatouay
@Tatouay If I'll add a note about wanting to use TDD approach will it focus the question?Weatherbeaten
I agree with @user2340612, you shouldn't be trying to do that. You should be testing your public api, not internal implementation.Spearwort
@diegomarin you comment can be extended to a valid answerWeatherbeaten
package-private doesn't do it in Java, unless you put each class into its own package. internal really is what you should use for this purpose.Timbre
M
4

Formally it is not possible to do this honestly on JVM, because class couldn't be open for subset of possible interiters.

However it can be partially done by the following trick:

open class SomeClass internal constructor(val configurableParameter: Int) {
    companion object {
        private const val defaultInput = 123

        fun create() = SomeClass(defaultInput)
    }
}

The constructor of this class can be called only from the same module (or from tests). And class is public, so anyone can use it. However from external modules you have only two ways of the class construction: companion object or reflection.

And finally you couldn't inherit from this class at any other modules, because constructor is internal.

Metamerism answered 3/12, 2019 at 16:5 Comment(4)
What's the benefit over internal ?Weatherbeaten
This class can be used everywhere, however it can be created only internally. It means, that you can inherit it from tests (because tests are at the same package), however it isn't possible to do this from any other modules.Metamerism
Just making sure, in kotlin maximum limit for class/method to be open for testing is module level?Weatherbeaten
@user7294900, no limits.Metamerism
R
3

For Android developers only, there's AndroidX VisibleForTesting annotation

Denotes that the class, method or field has its visibility relaxed, so that it is more widely visible than otherwise necessary to make code testable

Ricks answered 22/9, 2021 at 8:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.