Methods 是否可以使用Mockito以紧凑的方式验证任意交互?

Methods 是否可以使用Mockito以紧凑的方式验证任意交互?,methods,mocking,call,mockito,Methods,Mocking,Call,Mockito,很容易验证Mockito中的mock对象上是否发生了特定交互(特定方法调用),并且有verifyzerotations()用于检查是否根本没有发生交互。假设我正在使用info(),warn(),error()等方法测试一个类似于记录器的接口。在特定的场景中,我知道应该调用其中一个方法,但我并不真正关心哪一个。是否有一种简洁的方法可以检查与模拟对象的任何交互是否发生,而无需指定应该调用哪个方法?或者,也许这种机制是不必要的,因为测试它的“Mockito方式”与我想象的不同?使用log4j,要测试记

很容易验证Mockito中的mock对象上是否发生了特定交互(特定方法调用),并且有
verifyzerotations()
用于检查是否根本没有发生交互。假设我正在使用
info()
warn()
error()
等方法测试一个类似于记录器的接口。在特定的场景中,我知道应该调用其中一个方法,但我并不真正关心哪一个。是否有一种简洁的方法可以检查与模拟对象的任何交互是否发生,而无需指定应该调用哪个方法?或者,也许这种机制是不必要的,因为测试它的“Mockito方式”与我想象的不同?

使用log4j,要测试记录器,我需要执行以下设置:

@Mock private Appender log4jAppender;
private Logger logger;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);

    Logger root = Logger.getRootLogger();
    if (!root.getAllAppenders().hasMoreElements()) {
        // No appenders means log4j is not initialized!
        BasicConfigurator.configure();
    }
    logger = Logger.getLogger(MyClassWhichLogs.class);
    logger.addAppender(log4jAppender);
}
然后在我的测试中,我做了以下几点:

verifyZeroInteractions(log4jAppender);

如果您需要测试记录的值,您可以提供捕获器:

ArgumentCaptor<LoggingEvent> logCaptor = ArgumentCaptor.forClass(LoggingEvent.class);
verify(log4jAppender).doAppend(logCaptor.capture());
assertTrue(logCaptor.getValue().contains("my text to match");
ArgumentCaptor logCaptor=ArgumentCaptor.forClass(LoggingEvent.class);
验证(log4jAppender.doAppend(logCaptor.capture());
assertTrue(logCaptor.getValue().contains(“要匹配的我的文本”);

虽然这不一定能回答一般化的问题(我不认为你在寻找什么),它可能会解决测试日志记录的这个特定问题。

如果您可以从被测试的类中外部化logger对象的创建,那么您就没有理由不能编写自己的日志接口测试实现,该测试实现将记录已使用的方法,并将其作为测试设置的一部分注入

模拟库做了很多好事,但有时也会有一些像您发现的那样的角落案例,它们可能无法满足您的需求

如果您编写自己的实现来进行这样的测试,并将其注入到测试中的T测试类中,那么您可以在
getCount()>0

public class LoggerTestSupportImpl implements ILogger {

    private int count = 0;

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void info(String message) {
        count++;    
    }

    @Override
    public void warn(String message) {
        count++;    
    }   
}

这正是我到目前为止一直在测试我的类的方式,我只是想知道Mockito是否可以让我不用为所有方法编写琐碎的实现。我想说你一直在做明智的事情Michal。Mockito不支持这种测试。你唯一的选择就是按照前面提到的
ArgumentCaptor
路线由Kevin提出,但这会在测试类中产生很多“噪音”。同意这有点噪音,但大多数噪音都局限于声明和Before方法,如果要跨多个测试方法使用,甚至可以将Captor添加到类级声明中(如果不访问MSG,甚至不需要)。使用Mockito的好处在于,您已经可以访问完整的日志API。要在示例中这样做,您必须扩展手动mock的功能(捕获/检索任意记录的消息等)但对于简单的需求,您的方法似乎更简单、更干净、可重用,因此这些都是您的方法的优点。遗憾的是,此解决方案显然没有任何速记符号。有人知道为什么Mockito API允许测试“无交互”,但不允许测试否定,即“任何交互”吗?如果不是一个根据结果检查条件并抛出异常的方法(
verifyZeroInteractions()
),而是一个返回状态的布尔方法,我可以编写
assertTrue(anyInteractions(mock))
assertFalse(anyInteractions(mock))
。我可以尝试/catch
AssertionError
并以这种方式检查我的条件,但那太疯狂了。有人可能会认为单元测试应该能够确定要调用哪些方法,以及尝试测试“any”交互不是正确的测试。您是否无法在启用已知日志级别的情况下执行特定场景?
public class LoggerTestSupportImpl implements ILogger {

    private int count = 0;

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void info(String message) {
        count++;    
    }

    @Override
    public void warn(String message) {
        count++;    
    }   
}