我有一个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查找?我错过了任何嘲弄的步骤吗?
在第一次测试之前,尝试通过注入处理器初始化邮箱对象。
mail=new Mailbox(处理器);
不能说肯定没有调试,但它看起来像MyApplication.getApplication Context()
返回null
。
与其将其存储在静态变量中,不如尝试在@Service
类中需要的地方注入ApplicationContext
:
@Autowired
private ApplicationContext appContext;
Spring方面,您的代码看起来不太好,尤其是不可单元测试。我会解释:
邮箱
服务在任何级别都不应该知道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>失败,所以我认为它一定是错误的,但我不知道在哪里。谢谢。