Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito - Creating nested mock objects

Tags:

java

mockito

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!

like image 532
masT Avatar asked Nov 06 '13 12:11

masT


3 Answers

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);
like image 126
Adam Arold Avatar answered Oct 20 '22 07:10

Adam Arold


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!

like image 4
gmeiner.m Avatar answered Oct 20 '22 08:10

gmeiner.m


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.

like image 2
Debojit Saikia Avatar answered Oct 20 '22 06:10

Debojit Saikia