10

I'm learning Mockito. I am facing problem while creating mock for nested objects. See

public interface BaseManager {
    public Query createQuery(String queryString);
}

and an implementation class for that

public class BaseManagerImpl implements BaseManager {
    @Autowired
    private SessionFactory sessionFactory;
    // ...
}

Module level hibernate manager, for example:

public interface RegistrationManager {
    @Transactional
    public List<Country> getCountries();
}

and an implementation class for that

public class RegistrationManagerImpl implements RegistrationManager {
    @Autowired
    private BaseManager baseManager;
    // ...
}

Now I'm facing problem in creating mocked base manager. My test class is:

 public class MockitoTest {
    private RegistrationManager registrationManager = new RegistrationManagerImpl();

    @Mock private BaseManager baseManager;

    @Mock private SessionFactory sessionFactory;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    //  baseManager.setSessionFactory(sessionFactory);
        registrationManager.setBaseManager(baseManager);
    }
    // ...
    // @Test
}

Problem: sessionFactory is not instantiated inside baseManager. Please help creating mock object. Thanks in advance!

masT
  • 804
  • 4
  • 14
  • 29
  • 1
    What do you mean, "NullPointerException inside baseManager?" You have mocked your `baseManager` object -- it shouldn't be executing any code that you have not stubbed. There is more you are not showing in this example; please post the actual JUnit test and the *full* stacktrace. – Thorn G Nov 06 '13 at 12:59

3 Answers3

5

The problem is that you are creating a mock of BaseManager but only BaseManagerImpl has a SessionFactory field. Mockito doesn't know about BaseManagerImpl. In your code you create two mocks which are completely independent of each other.

Unit tests are about testing an unit. So you should test BaseManagerImpl and RegistrationManagerImpl separately.

So you test BaseManagerImpl first:

public class BaseManagerImplTest {

    private BaseManagerImpl target;

    // ...
}

then you test RegistrationManagerImpl:

public class RegistrationManagerImplTest {

    private RegistrationManagerImpl target;

    // ...
}

I suggest that you should use the name target or something similar for your test target in your test class becaues it will make your code much more easier to read.

Another thing: If you test an object all of its dependencies should be mocked but you shouldn't care about the mocks' dependencies. You just mock their method invocations like:

Mockito.when(myMock.someMethod()).thenReturn(someResultObject);
Adam Arold
  • 29,285
  • 22
  • 112
  • 207
  • you are absolutely right. We should not worry about mock's dependencies. But I have a problem like, I have service ServiceA.methodA() which is calling ServiceB.methodB(..), from methodB(...) it is calling ManagerC.serviceC(...). In this case, I want to mock only ManagerC.serviceC(...) and want a real call for ServiceB.methodB(..) because I do not want to mock my business layer. In this case, I have a same problem as one who asked this question. How can I achieve this? – Ketan Jun 11 '14 at 05:59
  • I don't understand this. What do you mean by `real call`? – Adam Arold Jun 11 '14 at 11:35
  • I mean FROM service (A.a1), i am making a call to some another service of the same class (A.a2) which in turn make a call to some other class's method (B.b1) and I want to mock only this (B.b1). How its possible ? – Ketan Jun 16 '14 at 10:48
4

You have to put the @InjectMocks annotation before class you want to test and mock the methods which are called by the basemanger or sessionFactory.

public class MockitoTest {
    @InjectMocks
    private RegistrationManager registrationManager = new RegistrationManagerImpl();

    @Mock private BaseManager baseManager;

    @Mock private SessionFactory sessionFactory;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    //  baseManager.setSessionFactory(sessionFactory);
        registrationManager.setBaseManager(baseManager);

        Mockito.when(baseManager.yourMethod()).thenReturn(someObject);
    }
    // ...
    // @Test
}

Hope this is it you're looking for!

gmeiner.m
  • 747
  • 5
  • 19
2

You cannot inject a mock of SessionFactory into a mock of BaseManager.

As you are testing RegistrationManagerImpl, you just need to have a mock of BaseManager. You can use method stubbing so that the methods BaseManager will return the stubbed values when those methods are called from RegistrationManagerImpl methods. So, if you have a RegistrationManagerImpl as this:

public class RegistrationManagerImpl implements RegistrationManager {
    @Autowired
    private BaseManager baseManager;
    // ...
    public String doSomething(){
         return baseManager.process();  
    }
}

you can write your MockitoTest as this:

public class MockitoTest {
    @InjectMocks
    private RegistrationManager registrationManager = new RegistrationManagerImpl();

    @Mock private BaseManager baseManager;

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

    }
    // ...
    @Test
    public void test() {
    when(baseManager.process()).thenReturn("hello");

    assertEquals("hello", registrationManager.doSomething());
    }
}

And while testing BaseManager, there you need to use mock of SeesionFactory.

Debojit Saikia
  • 10,532
  • 3
  • 35
  • 46