0

Problem: I can not verify or capture an argument passed to a private method of my System under Test.

For example:

public class FooManagedBean{

    public void persistFooEntity(){
        Response response = new Response();
        response.addResponse(checkFirstConstrain);
        response.addResponse(checkSecondConstrain(response));
        if(response.hasNoErros){
            persistFoo();
        }enter code here
    }

    private Response checkFirstConstrain(){
        Response response = new Response();
        if(//checking Constrain){
            return //Response with Error
        }
        return //Response without Error
    }

    private Response checkSecondConstrain(Response response){
        //some Code 
    }

}

First I tried to use Mockito.verify() to check the passed Response of the method checkSecondConstrain, which throws an Error, because you can only use it the Mock Instances. Second I tried it with ArgumentCaptor in order to capture the passed Response. But here we get the same Problem because to capture the passed argument you must use Mockito.verify().

Question: Is there a way to capture or verify an argument which is passed to a private method of the System under Test? I want the state of the variable while being passed to the method.

Another Question: Is it possible to verify if a method of the System under Test is invoked or rather is never invoked?

Note: FooManagedBean is the System Under Test.

System: Java 8, Mockito 1.9.5

Owic98
  • 1
  • 2
  • 1
    You should refactor your code to make it testable. – tgdavies Aug 03 '22 at 10:37
  • Check this - https://stackoverflow.com/questions/6913325/annotation-to-make-a-private-method-public-only-for-test-classes – Ashishkumar Singh Aug 03 '22 at 10:41
  • Yea I know I could move my checks into my Business Class and Mock it, but since these constraints are small I wanted them to be within the persist Methode. – Owic98 Aug 03 '22 at 12:19

1 Answers1

0

I would move the constraint-checking part into a separate class and make the methods public. This way, you can pass a 'ConstraintChecker' Mock and verify whatever you want.

public class ConstraintChecker {
  public Response checkFirstConstraint() {
    // ...
    return new Response();
  }

  public Response checkSecondResponse() {
    // ...
    return new Response();
  }
}

Which you then cann pass into your foo-managed-bean:

public class FooManagedBean {

  private final ConstraintChecker constraintChecker;

  public FooManagedBean(ConstraintChecker constraintChecker) {
    this.constraintChecker = constraintChecker;
  }

  public void persistFooEntity() {
    Response response = new Response();
    response.addResponse(constraintChecker.checkFirstConstraint());
    respones.addResponse(constraintChecker.checkSecondConstraint(response));
    if (response.hasNoErrors()) {
        persistFoo();
    }
  }
}

And in your test:

    @Test
    public void testFoo() {
      ConstraintChecker constraintChecker = Mockito.mock(ConstraintChecker.class);
      FooManagedBean bean = FooManagedBean(constraintChecker);

    
      Mockito.when(constraintChecker.checkFirstConstraint()).thenReturn(new Response());
      Mockito.when(constraintChecker.checkSecondResponse()).thenReturn(new Response());
            
      bean.persistFooEntity();

      Mockito.verify(constraintChecker).checkFirstConstraint();
      Mockito.verify(constraintChecker).checkSecondResponse();
   }
  • Instead of just making the methods public, you can use `@VisibleForTesting(otherwise = PRIVATE)` so the IDE catches you and throws a warning when you try to use them outside of tests. – Shark Aug 03 '22 at 11:44
  • Thanks for the answer, but I wanted to know if it is possible to verify it without a seperate class. I already have a business class which includes several Checks and other things where I can use the `Mockito.verify()`. – Owic98 Aug 03 '22 at 12:26
  • I mean if you really have to, you can make the methods package-private (without public/private etc.). And then instead if just instantiating your FooManagedBean, you can instead create a Mockito spy: `Mockito.spy(FooManagedBean.class)`. This will behave the same as the actual instance of your bean but you will be able to do `Mockito.verify` on it (or even mock some of the methods). – Kristian Ferkić Aug 03 '22 at 14:51
  • BTW. `@VisibleForTesting` is an Android-Annotation: https://developer.android.com/reference/androidx/annotation/VisibleForTesting so not available in non-android projects. And also, you technically still have to make the method public. The annotation is just a hint for your IDE. – Kristian Ferkić Aug 03 '22 at 14:54