【问题标题】:Mockito and ReloadableResourceBundleMessageSource doesn't go well together?Mockito 和 ReloadableResourceBundleMessageSource 不能很好地结合在一起?
【发布时间】:2015-12-02 07:46:15
【问题描述】:

我有这个简单的测试,它甚至不是一个测试,因为我只是想模拟消息源。

我收到此错误:

org.springframework.context.NoSuchMessageException: No message 
found under code '' for locale 'null'.

其他人可以验证此行为吗?

这是我设置的最小 Spring Boot 骨架测试,因为 ReloadableResourceBundleMessageSource 在另一个项目中不起作用,所以我想我会尽可能以最小的单位尝试它。

@RunWith(MockitoJUnitRunner.class)
public class DemoApplicationTests {

    @Test
    public void contextLoads() {

    ReloadableResourceBundleMessageSource messageSource = 
    mock(ReloadableResourceBundleMessageSource.class);
    when(
       messageSource.getMessage(
           anyString(), 
           any(Object[].class), 
           any(Locale.class)
         )
       ).thenReturn("returnValue");

    System.out.println("test");

    } 
}

这是我得到的错误:

org.springframework.context.NoSuchMessageException: No message 
found under code '' for locale 'null'.

at org.springframework.context.support.AbstractMessageSource.getMessage(
AbstractMessageSource.java:159)
at com.example.DemoApplicationTests.contextLoads(
DemoApplicationTests.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at ....
....
....
....
com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(
JUnit4IdeaTestRunner.java:117)
at com.intellij.rt.execution.junit.JUnitStarter.
prepareStreamsAndStart(
JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(
JUnitStarter.java:74)

在我看来,它无法正确模拟它。我也尝试过模拟MessageSource 接口,但无济于事。

【问题讨论】:

  • 我不知道你的问题是什么,但是不能存根getMessage的原因是因为它在AbstractMessageSource中声明了final,它是ReloadableResourceBundleMessageSource的超类. Mockito 不能存根 final 方法。
  • 谢谢,这就解释了!

标签: java unit-testing junit mockito


【解决方案1】:

正如大卫·华莱士所说:

Mockito 不能存根“final”方法,并且因为 'getMessage' 被声明为 final,所以你不能模拟它。

【讨论】:

  • 您的回答基本上是对@DavidWallace 评论的抄袭。您可以通过提及能够mock final methods 的 PowerMock 来扩展您的答案
  • 它是我评论的副本这一事实并没有错。 OddBeck 通过发布这个做了正确的事情,而我太懒了。他/她甚至正确地归因于它。这不值得一票否决。
  • 感谢大卫 W! @RomanVottner:我不知道 PowerMock,如果我知道 Mockito 和 final 方法的问题,我可能根本不会问这个问题。
【解决方案2】:

我不想使用 PowerMock,我解决了创建一个真正的 ReloadableResourceBundleMessageSource bean 并将它注入到我想要测试的类中的问题

// create the real bean
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(-1);
messageSource.setBasenames("classpath:conf-test/messages"); // this folder is just for testing and it contains a messages_en.properties file

// inject the bean into the class I wanted to test
ReflectionTestUtils.setField(service, "messageSource", messageSource);

【讨论】:

    【解决方案3】:

    在这种情况下,我找到了一种解决方法来模拟最终方法的 mockito 限制。

    我没有模拟,而是在构造它之后设置类:

    ReloadableResourceBundleMessageSource bundleMessageSource = new ReloadableResourceBundleMessageSource();
    bundleMessageSource.setUseCodeAsDefaultMessage(true);
    

    根据official documentation

    返回是否使用消息代码作为默认消息而不是 抛出 NoSuchMessageException。有利于开发和 调试。默认为“假”。

    【讨论】:

    • 既然上面只返回消息代码,我们可以得到消息吗?
    【解决方案4】:

    Final 方法不能模拟。所以我写了一个这样的解决方案。

        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setUseCodeAsDefaultMessage(true);
        ReflectionTestUtils.setField(service, "messageSource", messageSource);
    

    【讨论】:

      猜你喜欢
      • 2016-06-23
      • 1970-01-01
      • 2012-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      相关资源
      最近更新 更多