问题
I have a unit test that is failing and I'm unsure why. I want to be able to see all invocations on the mock that occur in the System Under Test. This is not the behavior that I want for all tests always, simply for a test that I need to quickly tweak to be able to figure out what's wrong.
However, it seems kind of like a hack. Is it possible to do this natively in Mockito, without having to use Thread.currentThread().getStackTrace()
?
This is not preferred, because the stack trace includes all the other invocations used internally by Mockito.
回答1:
This feature is builtin since Mockito 1.9.5. Just use
mock(ClassToMock.class, withSettings().verboseLogging())
回答2:
From Mockito 1.9.5
you can inspect a mock with MockingDetails Mockito.mockingDetails(Object mockToInspect).
You can either dig into the MockingDetails
properties by invoking : getMock()
, getStubbings()
, getInvocations()
and so for ... or simply use the printInvocations()
method that returns :
a printing-friendly list of the invocations that occurred with the mock object. Additionally, this method prints stubbing information, including unused stubbings. For more information about unused stubbing detection see MockitoHint.
For example with JUnit 5 :
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mock;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
public class FooTest {
Foo foo;
@Mock
Bar bar;
@Test
void doThat() throws Exception {
Mockito.when(bar.getValue())
.thenReturn(1000L);
// ACTION
foo.doThat();
// ASSERTION
// ...
// add that to debug the bar mock
System.out.println(mockingDetails(bar).printInvocations());
}
}
And you get an output such as :
[Mockito] Interactions of: Mock for Bar, hashCode: 962287291 1. bar.getValue(); -> at Foo.doThat() (Foo.java:15) - stubbed -> at FooTest.doThat(FooTest.java:18)
Note that the classes with a referenced line in the output are links to your source code/test class. Very practical.
回答3:
I was able to determine a method that does use Thread.currentThread().getStackTrace()
, and looping through the elements. It is ugly, but it does do the job. I hope another answerer will have a better method.
- Create an
InvocationListener
, and pass it the class name of the System Under Test. - Pass the listener into
Mockito.withSettings().invocationListeners()
- Temporarily modify the test to create the Mock with this
MockSettings
object.
Code of the InvocationListener
:
public static class DebugInvocationListener implements
InvocationListener {
private final String className;
public DebugInvocationListener(Class<?> klass) {
this(klass.getName());
}
public DebugInvocationListener(String className) {
this.className = className;
}
@Override
public void reportInvocation(MethodInvocationReport report) {
System.out.println(report.getInvocation());
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
for(StackTraceElement element : trace) {
if(element.getClassName().equals(className)) {
System.out.println(element);
System.out.println();
break;
}
}
}
}
来源:https://stackoverflow.com/questions/24294277/how-to-use-mockito-to-show-all-invocations-on-a-mock