How to use VisibleForTesting for pure JUnit tests

120,714

Solution 1

The Tag itself helps with the linter to identify unwanted access.

To lower the risk of use it directly, add this methods as internal in Kotlin or protected in Java instead of public and with that only the tests or classes that are in the same package will be able to access that method.

Java:

@VisibleForTesting
protected Address address() {
  return mAddress;
}

Kotlin:

@VisibleForTesting
internal fun address(): Address {
  return address;
}

Solution 2

Make the method package-private and the test will be able to see it, if the test is in the corresponding test package (same package name as the production code).

@VisibleForTesting
Address getAddress() {
  return mAddress;
}

Also consider refactoring your code so you don't need to explicitly test a private method, try testing the behaviour of a public interface. Code that is hard to test can be an indication that improvements can be made to production code.

The point of an annotation is that its convention and could be used in static code analysis, whereas a comment could not.

Solution 3

According to the Android docs:

You can optionally specify what the visibility should have been if not for testing; this allows tools to catch unintended access from within production code.

Example:

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public Address getAddress()

Solution 4

@VisibleForTesting annotation is used in package-methods in Guava, and does not part of JUnit API. The annotation is just a tag to indicate the method can be tested. It even doesn't be loaded in JVM.

Share:
120,714

Related videos on Youtube

Daniel Gomez Rico
Author by

Daniel Gomez Rico

Me

Updated on January 25, 2021

Comments

  • Daniel Gomez Rico
    Daniel Gomez Rico over 3 years

    I´m running pure JUnit4 java tests over my pure java files on my project but I can't find a way to use @VisibleForTesting clearly without making the thing manually public.

    Ex:

    @VisibleForTesting
    public Address getAddress() {
      return mAddress;
    }
    

    The method has to be public to let it be "public" to tests, but in that case the annotation doesn't make sense right? why not just use a comment if the annotation will not do nothing?

  • mpellegr
    mpellegr over 5 years
    not sure why this has so many more up votes. it's the same as the accepted answer except it's much less flexible the accepted answer doesn't require you to put your production code into the same package as your unit tests.
  • mpellegr
    mpellegr over 5 years
    "Also consider refactoring your code so you don't need to explicitly test a private method, try testing the behavior of a public interface." disagree with this. sometimes you need to do dependency injection by passing a set of arguments into some class A that creates some object fro class B. I had to create a public constructor for class B so class A could use that directly instead of class Bs getInstance() method. The accepted answer worked for me, I couldn't move my units tests into different packages to make this work. This seems like a workaround to me and the accepted answer is better.
  • Gerrit Sedlaczek
    Gerrit Sedlaczek over 5 years
    @mpellegr however it does improve the overall readability of the code. Especially for new developers.
  • Andy Marchewka
    Andy Marchewka over 2 years
    @MikeJ, can you please expand on the comment: "Also consider refactoring your code so you don't need to explicitly test a private method." One method/function should have one responsibility. If it has knowledge of a given class' implementation then it may be private, but it can still be very useful to test it against various inputs.
  • winne2
    winne2 over 2 years
    From the annotation's JavaDoc: "<b>Do not use this interface</b> for public or protected declarations." The other answers are correct, such methods should have package visibility in Java.
  • MikeJ
    MikeJ about 2 years
    If a test is written to test behaviour, and not the implementation it would be possible to refactor a public method by splitting it out some into a private method, and the existing tests would still cover the private method. TDD is good for this, as the test is done first before the implementation. The key is to test the behaviour, covering all the inputs from the publicly accessible API for the Class Under Test. It's much harder to write tests to cover a private method after it's implemented. By testing behaviour, you can refactor the production code without having to change the test code.