使用 mockito 在 JUnit 中模拟 ReentrantReadWriteLock

Mocking ReentrantReadWriteLock in JUnit with mockito

在我的实现中class我有一个读写锁定义如下,

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

我在一个名为 run() 的方法中使用它,

rwLock.writeLock().lock();

锁定进程。但是当我尝试用 mockito 测试它时,我发现 ReentrantReadWriteLock 已初始化。但是当我试图获得 rwLock.writeLock() 时,它是空的。这是我的测试。

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

如我所说,rwLock.writeLock() 为空,但 rwLock 已初始化。请解释 mockito 是如何发生这种情况的。执行此操作的理想方法是什么?

你搞错了:

@Mock
private ReentrantReadWriteLock feedReadWriteLock;

上面的 创建了 一个模拟,然后你 不知何故 必须进入你的 class测试.

但是这个:

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

是假的。 InjectMocks 注释的存在是为了 "getting it into" 为您完成这一部分。

换句话说,你应该这样做:

@Mock
private ReentrantReadWriteLock feedReadWriteLock;

@InjectMocks
private CustomModule module = new CustomModule();

例如。换句话说:你做 not mock 你的 class 被测实例。您创建一个 "real" 实例 - 然后您必须 "insert" 所需的模拟对象 进入 那个真实实例。 mocking 被测试的 class 绝对没有意义。因为您想测试 您的 代码,而不是模拟框架为您模拟的代码。

InjectMocks 注释试图为您做到这一点(使用反射和各种黑魔法)。不幸的是,当它不能完成它的工作时,它只会默默地失败。

从这个意义上说,答案是:不要只是盲目使用东西。您必须完全理解您写下的每一行代码。因此:阅读 this 以了解这些注释之间的区别。

谨记:请注意,您还必须使用 Mockito JUnitRunner 或手动调用 Mockito.initMocks() 才能让注释发挥作用。

如果你想模拟测试中的class,你应该使用@Spy

@RunWith(MockitoJUnitRunner.class)
public class CustomModuleTest {
    @Mock
    private ReentrantReadWriteLock feedReadWriteLock;

    @Spy
    @InjectMocks
    private CustomModule module;

    @Test
    public void test() {
        doReturn(feedReadWriteLock).when(module).getReadWriteLock();
        cacheJob.run();
    }
}

请注意,间谍的语法与模拟的语法略有不同。间谍允许您实例化真实对象,但可以根据需要模拟一些方法。

在这里,我return feedReadWriteLock,它被注释为@Mock,这样,您也许可以改变它的行为。您不想 return 一个新实例,就像您在示例中所做的那样。