简体   繁体   English

如何使用 Mockito 在模拟上显示所有调用

[英]How to use Mockito to show all invocations on a mock

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() ?是否可以在 Mockito 中本地执行此操作,而不必使用Thread.currentThread().getStackTrace()

This is not preferred, because the stack trace includes all the other invocations used internally by Mockito.这不是首选,因为堆栈跟踪包括 Mockito 内部使用的所有其他调用。

This feature is builtin since Mockito 1.9.5.此功能自 Mockito 1.9.5 起内置。 Just use只需使用

mock(ClassToMock.class, withSettings().verboseLogging())

From Mockito 2.2.6 you can inspect a mock with MockingDetails Mockito.mockingDetails(Object mockToInspect) .从 Mockito 2.2.6 开始,您可以使用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 :您可以通过调用以下getMock()来深入了解MockingDetails属性: getMock()getStubbings()getInvocations()等等...或者简单地使用返回的printInvocations()方法:

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.有关未使用的存根检测的更多信息,请参阅 MockitoHint。

For example with JUnit 5 :以 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.非常实用。

I was able to determine a method that does use Thread.currentThread().getStackTrace() , and looping through the elements. 我是能够确定确实使用方法Thread.currentThread().getStackTrace()并通过元件循环。 It is ugly, but it does do the job. 这很丑陋,但确实可以完成这项任务。 I hope another answerer will have a better method. 我希望另一位回答者能有更好的方法。

  1. Create an InvocationListener , and pass it the class name of the System Under Test. 创建一个InvocationListener ,并将其传递给受测系统的类名。
  2. Pass the listener into Mockito.withSettings().invocationListeners() 将监听器传递给Mockito.withSettings().invocationListeners()
  3. Temporarily modify the test to create the Mock with this MockSettings object. 暂时修改测试以使用此MockSettings对象创建Mock。

Code of the InvocationListener : 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;
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM