0

I have a variable of type Function like:

Class SomeClass{ 
    static final Function<Throwable, Optional<String>> SOME_FUNCTION = throwable -> Optional.empty();
}

I am wondering how to verify it was called for certain times and was passed in certain arguments?

What I need is the equivalent of the following code:

verify(SomeClass, times(2)).SOME_FUNCTION(any(Exception.class));

Thanks in advance!

Tirion
  • 117
  • 1
  • 2
  • 11

1 Answers1

0

You need to replace SOME_FUNCTION with a Mockito mock that you can assert invocations on. Depending on your situation, there might be several ways to achieve this:

Pass in the function as a member

If the function you need to perform assertions on does not necessarily need to be final static, and it makes sense in your situation to pass it in:

class MyClass {
    final Function<Throwable, Optional<String>> someFunction;

    public MyClass(Function<Throwable, Optional<String>> someFunction) {
        this.someFunction = someFunction;
    }

    // ...
}

then you can pass in a mock in your test:

Function<Throwable, Optional<String>> mockFunc = Mockito.mock(Function.class);
var myClass = new MyClass(mockFunc);
// ... test code ...
verify(mockFunc, times(2)).apply(any(Exception.class));

If the function needs to stay static but you still can make the variable non-final, then you can just change it by static assignment and it should work the same. Just remember to set it back to its original value afterwards in this case.

Mock the static member using reflection

If you cannot alter the class' code, and need to perform assertions on the static function, it becomes a bit more tricky. You can attempt to replace the function with a mock using reflection. Mockito has a Whitebox class which encapsules some of that:

Function<Throwable, Optional<String>> mockFunc = Mockito.mock(Function.class);
Whitebox.setInternalState(MyClass.class, "SOME_FUNCTION", mockFunc);
// ... test code ...
verify(mockFunc, times(2)).apply(any(Exception.class));

But this most probably has some unwanted side effects (like SOME_FUNCTION staying a mock longer than intended) and should only be a last resort.

Felk
  • 7,720
  • 2
  • 35
  • 65
  • I used the Whitebox approach but `java.lang.RuntimeException: Unable to set internal state on a private field. Please report to mockito mailing list.` occurred. Could you please help me with it? I already made the `SOME_FUNCTION` public (just for trial).. – Tirion Nov 06 '20 at 16:51
  • Hmm... Whitebox might work differently than I remember or you are using a version of Mockito I am not familiar with. You may try using `FieldSetter` instead: https://stackoverflow.com/a/51499019/3688648 or if that fails too, you could write some reflection code by hand. – Felk Nov 06 '20 at 16:57
  • I think `SOME_FUNCTION` cannot be `final`. After I deleted `final` it is OK. Thank you anyway! – Tirion Nov 06 '20 at 18:12