Search code examples
javaunit-testingjunitmockitopowermockito

Mocking ReentrantReadWriteLock in JUnit with mockito


In my implementation class I have a read write lock definition as follows,

@Inject
@Named("CustomizedLock")
private ReentrantReadWriteLock rwLock;

I'm using it in a method named run() as,

rwLock.writeLock().lock();

to lock the process. But when I'm trying to test this with mockito I found ReentrantReadWriteLock is initialized. But when I'm trying to get rwLock.writeLock() it's null. Here is my test.

@Mock
private ReentrantReadWriteLock feedReadWriteLock;

@InjectMocks
private CustomModule module = mock(CustomModule.class);

/////////////////////////

@Test
public void test() {
    when(module.getReadWriteLock()).thenReturn(mock(ReentrantReadWriteLock.class));
    PowerMockito.doReturn(new ReentrantReadWriteLock()).when(module.getReadWriteLock());
    cacheJob.run();
}

As I said rwLock.writeLock() is null but rwLock is initialized. Please explain how this happens with mockito. And what is the ideal way to do this?


Solution

  • You are getting mocking wrong:

    @Mock
    private ReentrantReadWriteLock feedReadWriteLock;
    

    The above creates a mock that you then somehow have to get into your class under test.

    But this:

    @InjectMocks
    private CustomModule module = mock(CustomModule.class);
    

    is bogus. The InjectMocks annotation exists to do that "getting it into" part for you.

    In other words, you should be doing something like:

    @Mock
    private ReentrantReadWriteLock feedReadWriteLock;
    
    @InjectMocks
    private CustomModule module = new CustomModule();
    

    for example. In other words: you do not mock an instance of your class under test. You create a "real" instance - and then you have to "insert" the required mock objects into that real instance. There is absolutely no point in mocking the class under test. Because you want to test your code, not something that the mocking framework mocked for you.

    The InjectMocks annotation tries to do that for you (using reflection and all kinds of black magic). Unfortunately when it can't do its job, it just silently fails.

    In that sense, the answer is: don't just blindly use stuff. You have to fully understand each and any line of code that you write down. Thus: read this to understand the difference between these annotations.

    And just for the record: please note that you also have to either use the Mockito JUnitRunner or to manually call Mockito.initMocks() in order have the annotations do their magic.