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

Mockito-mock ApplicationContext

颛孙铭
2023-03-14

我有一个Springboot应用程序,它在运行时根据用户传递的输入参数从ApplicationContext中查找bean。对于这种方法,我试图编写Mockito测试用例,但它不起作用,并抛出NullPointerException。

引导应用程序的类:

@SpringBootApplication
public class MyApplication {

    private static ApplicationContext appContext;
    
    public static void main(String[] args) {
        appContext = SpringApplication.run(MyApplication.class, args);
    }
    
    public static ApplicationContext getApplicationContext() {
        return appContext;
    }
    
}

我试图为其编写测试用例的类:

@Service
public class Mailbox {

    @Autowired
    MailProcessor processor;
    
    public void processUserInput(Envelope object) {
    
        processor.setCommand(MyApplication.getApplicationContext().getBean(object.getAction(), Command.class));
        processor.allocateEnvelopes(object);
        
    }
} 

我的测试用例如下:

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class MailboxTest {

    @Mock
    MailProcessor processor;
    
    @InjectMocks
    Mailbox mailbox;
    
    @Test
    public void testProcessUserInput() {
        
        Envelope message = new Envelope();
        message.setAction("userAction");
        message.setValue("userInput");
        
        doNothing().when(processor).setCommand(any());
        doNothing().when(processor).allocateEnvelopes(any());
        
        mailbox.processUserInput(message);
        
        Mockito.verify(processor).allocateEnvelopes(any());
        
    }
    
    
}

每当我运行测试用例时,它都会在处理器上给出NullPointerException。setCommand(MyApplication.getApplicationContext()。getBean(object.getAction(),命令。阶级) 邮箱类中。如何模拟ApplicationContext查找?我错过了任何嘲弄的步骤吗?


共有3个答案

家经纶
2023-03-14

在第一次测试之前,尝试通过注入处理器初始化邮箱对象

mail=new Mailbox(处理器);

赫连宏伯
2023-03-14

不能说肯定没有调试,但它看起来像MyApplication.getApplication Context()返回null

与其将其存储在静态变量中,不如尝试在@Service类中需要的地方注入ApplicationContext

@Autowired
private ApplicationContext appContext;
俞新翰
2023-03-14

Spring方面,您的代码看起来不太好,尤其是不可单元测试。我会解释:

  1. 您的邮箱服务在任何级别都不应该知道MyApplication。它是spring boot应用程序的入口点,您的业务逻辑不应该依赖于此。确实,您可以将应用程序上下文直接注入到类中。请参见下面的示例。这里的另一个(更“老派”的)选项是在邮箱服务中使用ApplicationContextAware接口(参见本例)。然而,这仍然是一个糟糕的代码:
@Service
public class Mailbox {
 private final ApplicationContext ctx;
 ...
 public Mailbox(ApplicationContext ctx) {
     this.ctx = ctx;
 }
 ...
}

即使您解决了这个问题,一般来说,依赖ApplicationContext也不是一个好主意。因为这样你就变得依赖于spring,而在Mailbox类中没有理由这样做。不过,这个类将成为单元可测试的。

在决议方面:

在Spring,你可以注入一个映射

public interface Command {
 void execute();
}

@Component("delete") // note this "delete" word - it will be a key in the map in the Mailbox
public class DeleteMailCommand implements Command {
    @Override
    public void execute() {
        System.out.println("Deleting email");
    }
}

@Component("send")
public class SendMailCommand implements Command{
    @Override
    public void execute() {
        System.out.println("Sending Mail");
    }
}

请注意,所有命令都必须由spring驱动(这似乎是您的情况)。现在,邮箱将如下所示:

@Service
public class Mailbox {
    private final Map<String, Command> allCommands;
    private final MailProcessor processor;
    // Note this map: it will be ["delete" -> <bean of type DeleteMailCommand>, "send" -> <bean of type SendMailCommand>]
    public Mailbox(Map<String, Command> allCommands, MailProcessor mailProcessor) {
        this.allCommands = allCommands;
        this.processor = mailProcessor;
    }

    public void processUserInput(Envelope envelope) {
        Command cmd = allCommands.get(envelope.getAction());
        processor.executeCommand(cmd);

    }
}

这个解决方案很容易进行单元测试,因为如果愿意,您可以用mock命令填充映射,而不需要处理应用程序上下文。

更新

我现在看了一下你的测试,它也不太好,对不起:)@RunBy(MockitoJUnitRunner.class)用于运行单元测试(根本没有Spring)。将此注释与运行完整系统测试的@SpringBootTest放在一起是没有意义的:启动整个Spring启动应用程序,加载配置等等。

因此,请确保要运行哪种类型的测试,并使用适当的注释。

 类似资料:
  • Mockito 是一个针对 Java 的 mocking 框架。它与 EasyMock 和 jMock 很相似,但是通过在执行后校验什么已经被调用,它消除了对期望行为(expectations)的需要。其它的mocking库需要你在执行前记录期望行为(expectations),而这导致了丑陋的初始化代码。

  • 本文向大家介绍mockito 使用Mockito批注,包括了mockito 使用Mockito批注的使用技巧和注意事项,需要的朋友参考一下 示例 我们要测试的类是: 它的合作者是: 在我们的测试中,我们想打破依赖关系Collaborator及其错误,因此我们将模拟Collaborator。使用@Mock注释是为每个测试创建不同的模拟实例的便捷方法: Mockito将尝试按以下顺序解决依赖项注入:

  • 问题内容: 我是Mockito的新手,我曾尝试研究此Exception,但未找到具体答案。当我同时使用两个模拟时,它会在我的代码中发生,这意味着我通过一个模拟的构造函数给出了另一个模拟。像这样: 在一个论坛中,我读到了关于不通过另一个模拟的构造函数发送模拟的消息,因为Mockito可能会与模拟调用混淆,因此我尝试了以下操作: 但无济于事。我确保只调用和,因为这些是类唯一的方法。我不明白发生了什么。

  • 我面临Mockito junit测试的问题。我是新手,对我面临的问题有点困惑。在此方面的任何帮助都将不胜感激。 获得异常: 在下面的代码中 我知道活动不是一种模拟,但我不确定是否有办法解决这个问题,因为 是同一类中的一种方法。我需要为编写规则,因为我已经完成了它的单元测试。的定义由外部依赖关系组成。我是否应该嘲笑中存在的外部依赖关系并为它们编写规则,而不是为规则? 我发现了这篇文章:Mockito

  • 我听从了@Hoaz的建议。但是,我得到了nullpointer异常 我还注意到DAO是null,所以我这样做了(只是为了提一下,我做了下面的步骤来尝试,我知道springUnit和Mockito或xyz之间的区别): 如何使用Mockito模拟外部方法调用 如何使用Mockito在模拟对象上设置属性?

  • 问题内容: 谁能总结一下,究竟什么功能使您在Mockito的基础上添加了PowerMock? 到目前为止,我已经找到了这些: 模拟静态,最终和私有方法 删除静态初始化器 允许在没有依赖项注入的情况下进行嘲笑-我不清楚这一点。你能详细说明吗? 它还会添加其他内容吗?您可以分几行进行总结吗? 使用PowerMock时需要牺牲一些东西吗? 问题答案: 我不知道还有其他好处,但是我想解决您的两个子问题(这

  • 本文向大家介绍mockito 简单的最小Mockito测试,包括了mockito 简单的最小Mockito测试的使用技巧和注意事项,需要的朋友参考一下 示例 此示例显示了使用嘲笑的最小Mockito测试ArrayList:            

  • 这将无法编译。我得到一个未完成的存根异常。我已经在这个网站上阅读了Mockito api和其他问题,我认为我的语法不应该是错误的,但它在doAnswer(new Answer(){/code>失败,所以我认为它一定是错误的,但我不知道在哪里。谢谢。