Rules S2039 and S2156 should recognize `@VisibleForTesting` other than Guava's

Rules

  • squid:S2039 (Member variable visibility should be specified)
    and
  • squid:S2156 (“final” classes should not have “protected” members)

accept Guava’s @VisibleForTesting (“com.google.common.annotations.VisibleForTesting”) annotation as an exception.

However, there are several other @VisibleForTesting annotations out there that serve the same
purpose and should be regarded as well.

For example, AssertJ provides a @VisibleForTesting annotation:
http://joel-costigliola.github.io/assertj/core-8/api/org/assertj/core/util/VisibleForTesting.html

Android provides another one: https://developer.android.com/reference/android/support/annotation/VisibleForTesting

All the aforementioned annotations should be recognized as exception; perhaps even
any annotation named "VisibleForTesting" regardless of its origin.

squid:S2039 (Member variable visibility should be specified)

Exceptions

Members annotated with Guava’s any @VisibleForTesting
annotation (Guava or other) are ignored, as it indicates that visibility has been purposely
relaxed to make the code testable.

import org.assertj.core.util.VisibleForTesting; // not Guava, but accepted
class Cone {
  @VisibleForTesting  Logger logger; // Compliant
}
class MyExample { 
  @org.assertj.core.util.VisibleForTesting
  int foo = 0;                      // Compliant
	
  @android.support.annotation.VisibleForTesting
  int bar = 42;                     // Compliant
  
  @org.just.some.example.VisibleForTesting
  int baz = 7;                      // Compliant

  private String color = "red";     // Compliant
  
  String name = "something";        // Noncompliant
}

squid:S2156 (“final” classes should not have “protected” members)

Exceptions

Members annotated with Guava’s any @VisibleForTesting
annotation (Guava or other) are ignored, as it indicates that visibility has been purposely
relaxed to make the code testable.

import org.assertj.core.util.VisibleForTesting;
public final class MyFinalClass {
  @VisibleForTesting
  protected Logger logger; // Compliant

  @android.support.annotation.VisibleForTesting
  protected int calculateSomethingComplex(String input) { // Compliant
    // ...
  }
}

hello @bduderstadt,

thank you for this well researched suggestion. I think it makes perfect sense, I created ticket for this improvement https://jira.sonarsource.com/browse/SONARJAVA-3122

1 Like