@InjectMock 是否只在 class 的全局变量中注入模拟?

Does @InjectMock only inject mocks in global variables of a class?

我尝试做以下测试:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;


@ExtendWith(MockitoExtension.class)
public class SomeClassTest {
    
    // needs to be mocked and injected
    @Mock
    private SomeDao someDao;

    @InjectMocks
    private SomeClass someClass = new someClass();

    @Test
    void test() {
       when(someDao.retrieveSomeData).thenReturn(10);
    }
}

这是简化的 class,其中实例化了我要注入的对象并在方法中使用:

public class SomeClass {
   private void someMethod() {
      SomeDao someDao = new SomeDao();
      someDao.retrievSomeData();
   }
}

但我也可以在构造函数中实例化 class 如下:

public class SomeClass{
   SomeDao someDao;

   public SomeClass() {
      someDao = new SomeDao();
   }

   private void someMethod() {
      someDao.retrievSomeData();
  }
}

结果: 它仍然是调用了真实对象 someDao.rerieveSomeData() 的真实函数,而不是我的模拟对象!为什么?我比较迷茫。

@InjectMock 可以通过三种方式注入模拟:

  1. 构造函数注入:如果您的 SomeClass 具有类型为 SomeDao 的构造函数参数,它将作为该参数传递模拟。
  2. Setter 注入:如果 SomeClass 有一个带有 SomeDao 类型参数的 setter 方法(例如 setDao(SomeDao dao) 或者有几个这样的 setters,但其中一个与 mock 同名(即 setSomeDao(SomeDao someDao)),它将以 mock 作为参数调用此 setter。
  3. 字段注入:如果有一个 SomeDao 类型的字段或有多个 SomeDao 类型的字段,但其中一个字段与您的 mock 同名(即 someDao), 它将用模拟设置这个字段。

对于您的代码,这意味着您不应该在 SomeClass class 中创建 SomeDao 的实例,而是注入它。在您的正常业务代码中,您将在 SomeClass 之外创建 DAO 并将其传递给构造函数(这通常是首选的注入变体)。在你的测试中,mockito 会注意做同样的事情,但使用模拟而不是真正的 DAO。