当前位置: 首页 > 知识库问答 >
问题:

使用Mockito重复回答处理。doAnswer(…)

濮阳浩穰
2023-03-14

我试图测试一个静态方法,它捕获来自不同子调用或方法本身的异常,并只记录异常消息。根据要求,我无法更改方法实现。在这种情况下,监视子调用不是一个选项,因为我们希望在测试期间保持一致,并且由于一些执行会从方法体本身引发异常,所以我们最终选择检查。。。错误日志消息

因此,我想模拟将从方法调用的记录器,当记录器调用错误(...)时,向日志记录调用添加一个答案,并与特定消息相匹配。到目前为止,我这边很好。我所做的一个例子如下:

Mockito.doAnswer(new Answer<Void>()
{
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        String errorMessage = (String) args[0];
        assertTrue(errorMessage.contains(SPECIFIC_MESSAGE));
        return null;
    }
}).when(logger).error(Matchers.startsWith(GENERIC_PREFIX));

我们决定使用PowerMockito来模拟静态调用,并从LoggerFactory.getLogger(...)

Logger logger = Mockito.mock(Logger.class); 
PowerMockito.mockStatic(LoggerFactory.class);
Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

现在我们的问题来了:

对于每个测试,要检查的特定消息的值都会发生变化。因此,我们为每个测试模拟一个记录器,模拟静态LoggerFactory调用以返回记录器,然后将我们的特定答案添加到记录器中。错误(…)打电话询问这个具体的例子。但是第一个答案被添加到记录器中。第一次测试中的错误调用似乎覆盖了所有其他答案。每次测试都会执行相同的操作。

我以为问题可能来自Mockito,它会返回一个单例模拟,但我测试了它,事实并非如此。然后我想我的问题可能来自我的争吵工厂。getLogger(…)调用,该调用将始终返回同一个记录器实例,但也不会返回该实例。下面是一个实现,它显示了我的代码与相关执行日志跟踪的相同问题。

import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App
{
    public static Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args)
    {
        logger.error("Error = " + Arrays.toString(args));
    }
}

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({LoggerFactory.class})
public class AppTest
{
    @Test
    public void firstTest()
    {
        Logger logger = Mockito.mock(Logger.class); 
        PowerMockito.mockStatic(LoggerFactory.class);
        Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

        Mockito.doAnswer(new Answer<Void>()
        {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String errorMessage = (String) args[0];
                System.out.println("Calling from firstTest");
                assertTrue(errorMessage.contains("a"));
                return null;
            }
        }).when(logger).error(Matchers.startsWith("Error"));

        App.main(new String[]{ "a" });
    }

    @Test
    public void secondTest()
    {
        Logger logger = Mockito.mock(Logger.class); 
        PowerMockito.mockStatic(LoggerFactory.class);
        Mockito.when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);

        Mockito.doAnswer(new Answer<Void>()
        {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String errorMessage = (String) args[0];
                System.out.println("Calling from secondTest");
                assertTrue(errorMessage.contains("b"));
                return null;
            }
        }).when(logger).error(Matchers.startsWith("Error"));

        App.main(new String[]{ "b" });
    }
}

跟踪:

Calling from firstTest
Calling from firstTest

知道为什么第二个答案没有被处理吗?提前感谢。

编辑:

问题实际上来自静态方法mock。“然后我想我的问题可能来自我的LoggerFactory。getLogger(…)调用,该调用将始终返回同一个记录器实例,但也不会返回该实例。“实际上是错误的。在调用getLogger(…)的测试中,它是有效的。”返回在测试中模拟但实际调用应用程序时模拟的记录器。主要的(…)方法,模拟的getLogger(…)main(…)内部的方法调用始终返回相同的实例,并且在测试之间不会按预期重置。根据文档,Mockito应该在测试之间重置。mockito的缺陷还是局限?与Mockito和PowerMockito之间的交互有关的问题?

共有1个答案

袁奇文
2023-03-14

我找到了一个解决方案,就是为每个测试在方法级别为类准备静态模拟。在签名之前添加@PrepareForTest(LoggerFactory.class)实际上解决了一个问题,即在测试和第一次调用Mockito之间没有重置记录器工厂模拟。when(LoggerFactory.getLogger(any(Class.Class)))。然后返回(记录器) 始终有效,并且始终返回相同的记录器。

 类似资料:
  • 是否有人使用RecyclerView找到了将onClickListener设置为RecyclerView中的项的方法? 请帮帮我...我是初学者:)

  • 我知道匹配模式解析器,这是Spring批处理提供的。我需要关于如何构造批处理作业的帮助,以便它可以读取循环中的记录类型5和记录类型6。

  • 我正在写基本的用户注册页面,我的注册页面包含:用户邮件,密码,计划类型。计划类型有三个计划。三种方案是:基本方案、银方案和金方案。 register_main.php是将用户信息存储在MySQL中。 我遇到的问题是,当我点击基本或银或黄金计划,页面将转到注册的主页。我只希望在他们单击“登录”时将用户信息发送到服务器。 有人能帮我解决这个问题吗? 超文本标记语言代码: register_main.p

  • 我是Swift新手,这段代码给了我一个错误,尽管它没有文本,但它还是通过了“lastname!=nil”。 线程1:致命错误:在展开一个可选值时意外地找到nil 我很困惑,不知道为什么验证不起作用

  • 河楼 我试图配置Hibernate本地开发与HSQL数据库,但我被困在Spring不处理事务。 配置数据源,会话工厂等... 本地环境具有hibernate配置的属性文件 引发异常的代码的调用点 调用人员Dao.saveOrUpdate()后打印的堆栈跟踪 我已经尝试过的 在HibernateTransactionManager/DatasourceTransactionManager之间切换 属