【问题标题】:Mocking Spring Bean模拟春豆
【发布时间】:2011-11-19 22:41:19
【问题描述】:

我有以下课程:

public class Plugin {

    private DistributionManager manager;

    public void init(){
          ApplicationContext context = 
                new ClassPathXmlApplicationContext("applicationContext.xml");
        manager = context.getBean(DistributionManager.class);
    }

    public String doSomething(){
        String s =  manager.doSomething();
            return doSomethingElse(s);
    }

DistributionManager 类本身有很多自动装配的依赖,标记为@Component

现在我想为所有这些代码运行一些单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
public class PluginTestCase extends  AbstractJUnit4SpringContextTests{

    @Resource
    DistributionManager manager;

    @Test
    public void testDoSomething(){
             Plugin plugin = mock(Plugin.class);

             //how can I inject DistributionMamanger bean to plugin using mockito?
             assertEquals("MyResult", plugin.doSomething());
    }

}

我以前从未使用过 mockito。你能帮我模拟插件并完成这个单元测试吗?

更新:

我正在根据建议尝试以下测试:

@RunWith(MockitoJUnitRunner.class)
public class PluginTestCase {

    @Mock
    DistributionManager manager;

    @InjectMocks 
    Plugin testedPlugin;

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

    @Test
    public void testDao(){
        testedPlugin.init();
        testedPlugin.doSomething();
    }
}

但是,我遇到了以下异常:

org.mockito.exceptions.base.MockitoException: Field 'testedPlugin' annotated with @InjectMocks is null.
Please make sure the instance is created *before* MockitoAnnotations.initMocks();
Example of correct usage:
   class SomeTest {
      @InjectMocks private Foo foo = new Foo();

      @Before public void setUp() {
         MockitoAnnotations.initMock(this);

    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl$1.withBefores(JUnit45AndHigherRunnerImpl.java:27)
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:261)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

【问题讨论】:

  • 如果您尝试对 Plugin 类进行单元测试,那您为什么要嘲笑它?
  • @scaffman,可能是我错了,我以前从未使用过模拟。我应该嘲笑什么?
  • 我不知道,您还没有告诉我们您要测试什么。您可能想阅读 Mockito 主页上的简单教程,以更好地了解您想要实现的目标。
  • 我正在尝试测试 plugin.doSomething() 但我需要以某种方式注入管理器 bean。

标签: java spring junit mocking mockito


【解决方案1】:

如果您要进行单元测试,请不要模拟 Plugin。是相反的!同样对于单元测试,我肯定会避免创建 spring 上下文,而是应该只在集成测试或一些非常罕见/特定情况下这样做。

无论如何,我想您想测试插件和管理器之间的交互。因此,您绝对应该阅读 Mockito 文档,但这是在插件中注入模拟管理器的第一个开始。

@RunWith(MockitoJUinitRunner.class)
public class PluginTest {
    @Mock DistributionManager mockedManager;
    @InjectMocks Plugin testedPlugin = new Plugin(); // initialization not need when using Mockito 1.9.x

    @Test public void plugin_should_call_the_the_manager_on_doSomething() {
        // given
        // when
        // then
    }

    // other scenarios
}

请注意,您只需要使用 JUnit 运行器 MockitoJUinitRunner.class 或实用程序类和方法 MockitoAnnotations.init(),但不能同时使用两者!

其他说明:

  • 当您使用 JUnit 4.x 时,您不需要让您的测试方法名称以 test 开头,因为它们由 @Test 注释,您可以将它们命名为任何您想要的可读和表达意图的名称测试。
  • 设置和拆除方法也是如此,因为它们分别由@Before@After 注释,您可以描述设置或拆除的内容。
  • 最后,不要将您的测试类命名为PluginTestCase,后缀TestCase 仅用于抽象类,这些抽象类将由以Test 为后缀的实际测试扩展,例如MyClassTest。无论如何,Maven Surefire 会查找名为 *Test 的类。

【讨论】:

  • 查看我的更新,另外根据您的回答,Mockito 将如何启动 Spring 上下文并获取 bean?
  • 哦,是的,我使用的是 Mockito 1.9rc,Mockito 1.8.5 需要您实例化需要注入的字段。查看消息异常,这很容易解释。 Mockito 努力提供良好的错误报告,以及正确使用其 API 的方式。 (我相应地更新了我的答案)。
猜你喜欢
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 2013-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多