Automatic visibility relaxation for unit tests

At least one language ( is it D? I forgot ) allows you to override visibility modifiers with a command line switch. This is useful when compiling unit tests, as it avoids things so commonly found in other languages:

@VisibleForTesting
public Foo foo;

@VisibleForTesting
void setTheBar(int value);

etc. It can also dramatically lessen the need for convoluted dependency injection techniques. C++ has the notion of a “friend class” that can ignore its visibility constraints.

All this has always seemed like a lot of sense to me. Visibility modifiers in the Java world provide two fairly separate things:

  • Ability to craft a well designed API so tools like IDEs and compilers can ensure you only use intended entry points.
  • Ability to sandbox code

The Java world has a standardised build layout and tools that automatically understand the difference between unit tests and main program code depending on where they are in the tree. It'd be nice if the Kotlin toolchain used these conventions to compile the main code twice: once in which everything is public for the unit tests to use, and again for the real shipping product. This would make the change transparent to API and sandboxing users, whilst avoiding the need to poke holes in visibility for testing.

For bonus points kotlinc could generate the two libraries in parallel, with a “last second” bytecode rewriting pass for the second jar making everything public.

I don’t know how easy this would be to implement, but it’d be a cool feature for possibly not much work and would solve a practical problem I’ve encountered many times in real Java codebases.

2 Likes

The Java world has a standardised build layout and tools that automatically understand the difference between unit tests and main program code depending on where they are in the tree.

Which I personally consider a terrible idea (as the navigation in the parallel tree takes much time). Recognizing tests based on their name (or an annotation) would be IMHO much better. But I can live with the tree.

It'd be nice if the Kotlin toolchain used these conventions to compile the main code twice: once in which everything is public for the unit tests to use,

This can backfire if your code uses reflection on itself or a library does it. You'd actually test a slightly different code, which may sometimes lead to passing a test despite a bug. But such problems are most probably rare and Java testing/mocking frameworks suffer bigger problems of this kind.

For bonus points kotlinc could generate the two libraries in parallel, with a "last second" bytecode rewriting pass for the second jar making everything public.

I don’t know how easy this would be to implement, but it’d be a cool feature for possibly not much work and would solve a practical problem I’ve encountered many times in real Java codebases.

I guess making everything public and non-final should be pretty trivial and ligtning fast compared to compilation. Jmockit does this and also more complicated things on the fly http://jmockit.github.io/about.html.

A good IDE support directly allowing you to call private methods and extend private classes in tests would be damn cool. I guess, I love this idea.

As Martin correctly observes, just making things public wouldn't work, for a number of reasons, the lesser being reflection and the greater — teh fact that methods will suddenly override or be overridden by something they did not override before.

But this is a technicality that we can solve. Answering the initial question: yes, we have this as a feature on the roadmap (http://youtrack.jetbrains.com/issue/KT-525), but it is not yet planned for any particular time frame (in other words, do not expect it very soon).

1 Like

Nice, you guys are way ahead of me.

I think it might be a good idea to define a special relationship between a class/artifact and its test class, so that everything is visible to the designated test class.

One way to achieve this it to treat the test class as inner class.