Java – Mocking Spring Bean

javajunitmockingmockitospring

I've the following class:

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 class itself has a lot of autowired dependencies and marked as @Component

now I would like to run some unit Test for all this code:

@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());
    }

}

I have never used mockito before. Can you please help me to mock plugin and complete this Unit test?

Update:

I'm trying the following test according to suggestion:

@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();
    }
}

but, I'm having the following exception:

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)

Best Answer

Don't mock Plugin if it's the class you want to Unit test. It's the opposite! Also for a unit test I would definitely avoid creating a spring context, instead you should only do that for integration testing or some very rare / specific case.

Anyway I suppose you want to test the interactions between the plugin and the manager. So you should definitely read the Mockito documentation but here's a first start that get a mocked manager injected in the plugin.

@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
}

Please note, that you only need to use eihter the JUnit runner MockitoJUinitRunner.class or the utility class and method MockitoAnnotations.init(), but not both!

Other remarks:

  • As you are using JUnit 4.x you don't need to make your test method name begin by test, as those are annotated by @Test you can name them as whatever you want that is readable and expressive on the intent of the test.
  • Same goes for set up and tear down methods, as they are respectively annotated by @Before and @After you can describe what your setting up or tearing down.
  • And finally, don't name your test class PluginTestCase, the suffix TestCase was only used for abstract classes that would be extended by an actual test suffixed by Test such as MyClassTest. And anyway Maven Surefire will look for classes named *Test.
Related Topic