3
votes

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.

1
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 ituser2340612
@user2340612 If I'll add a note about wanting to use TDD approach will it focus the question?user7294900
I agree with @user2340612, you shouldn't be trying to do that. You should be testing your public api, not internal implementation.Diego Marin Santos
@diegomarin you comment can be extended to a valid answeruser7294900
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.Alexey Romanov

1 Answers

2
votes

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.