4

Are the any ways to create method/contractor that could be used only in Junit ( test purpose only ) ?

Maybe there is an annotation?

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    Maybe the method could walk up the call stack, looking for some method that's annotated with @Test? (That is, as long as the method is in the same thread as the test.) – Andy Thomas Jul 02 '17 at 16:02
  • 1
    Andy: that would put a whole lot of complicated test only code in your production class. I would strongly advise to not do that. – GhostCat Jul 02 '17 at 16:22
  • Just wondering: are you looking for further input; or is there anything I could do to make my answer accept-worthy? – GhostCat Jul 04 '17 at 08:38

4 Answers4

4

For methods that are only used for testing... why not make them part of the actual test-code? At least in build-systems such as Maven, test code is not included in packaged jars, and is only distributed as part of the sources. In that sense, it cannot be called from normal classes, since it is simply not included in the final .jar (or .war).

I very frequently write such methods to make my test-code more maintainable.

To clarify:

src/
  main/
    java/
      my/package/
        MyClass.java <-- leave necessary protected accessors here
  test/
    java/
      my/package/
        MyClassTest.java <-- implement test-code here

And in MyClassTest...

public class MyClassTest {

   ...

   private static Foo doSomethingCoolButTesty(MyClass instance) {
       // access protected or package-private MyClass code here 
   }
}

MyClassTest.doSomethingCoolButTesty will be kept separate from the main code, and will obviously only be available to test code. Yes, it is somewhat uglier than including it as a method of the main code, but I find a fair price to pay.

tucuxi
  • 17,561
  • 2
  • 43
  • 74
  • in my case, class members are filled with de-serialized data out of JSONs, so no need for set methods in most cases. For testing though, the set methods are very beneficial. – Wolfson Aug 26 '20 at 13:01
1

There is nothing that would prevent to call methods "outside" of a junit test case.

My pragmatic answer: make the method package protected and add a simple comment like "unit test only" as javadoc. And educate your team to honor such statements.

And ideally: design your production code in a way that does not require such "tricks" in order to make it testable!

Given the comments on the question: it might be technically possible to somehow acquire stack trace information; to then search for the presence of @Test annotations on the corresponding methods. But that seems to be absolute overkill - and it would mean to add even more "test only" code into the production code.

And it would also be the wrong approach - as it tries to solve a "social" problem using technical means: if you don't want that people are calling a certain method - then make sure they understand that.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • well, to get really pedantic... you could try to access junit by introspection (Class.forName) inside the method, which would fail unless junit was available in the classpath, which generally corresponds to "being run in a test". This is hacky and slow and horrible, but would work most of the time. – tucuxi Jul 02 '17 at 16:53
  • Something that is slow and horrible doesn't meet my criteria for "working" :-) – GhostCat Jul 02 '17 at 17:43
1

For what purpose do you need this method?

(J)UnitTests should verify the behavior of the class by using its public interface. No "special" method in the tested code should be used in unit tests.


But Unittests should replace the dependencies of the tested code with test doubles (aka fakes and mocks). The preferred way to provide those test doubles is dependency injection (DI).

Sometimes its to much effort to introduce DI to your code. In that case it is acceptable to introduce low visibility getter methods as a seam where the dependency can be replaced by the mock.

class CodeUnderTest{
  private final SomeOtherClass dependency = new SomeOtherClass();
  SomeOtherClass getDependency(){ // package private getter
    return dependency;
  }
  public void doSomething(){
     dependency.expectedMethodCalled();
  }
}

class TestInSamePackage{
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();

     @Mock
     private SomeOtherClass testDouble;

     @Spy
     private CodeUnderTest cut;

     @Before
     public void setup(){
       doReturn(testDouble).when(cut).getDependency();
     }

     @Test
     public void shouldDoSomething() {
         // configure testDouble

         cut.doSomething();

         verify(testDouble).expectedMethodCalled();
     }
}
Timothy Truckle
  • 15,071
  • 2
  • 27
  • 51
0

Copied from How do I test a class that has private methods, fields or inner classes?

You can use reflection to get around the visibility of fields and methods. Others rightly pointed out that private functions should not be tested but I personally had the use case of writing into fields that under normal circumstances should not have a setter or any write access beside the constructor.

apoth
  • 13
  • 3