传递给子 class 的 Mockito 模拟对象未在 super 中使用

Mockito mocked object passed to child class not being used in super

我正在尝试模拟身份验证并在实例化子对象时传递模拟对象 class

GoogleOAuthService mockGoogleOAuthService = Mockito.mock(GoogleOAuthService.class);
mockGoogleOAuthService = Mockito.spy(mockGoogleOAuthService);
GoogleCredentials mockGoogleCredentials = Mockito.mock(GoogleCredentials.class);
mockGoogleCredentials = Mockito.spy(mockGoogleCredentials);
Mockito.when(mockGoogleOAuthService.authenticateServiceAccount(secretJson, SERVICE_ACCOUNT_SCOPES)).thenReturn(mockGoogleCredentials);
final HotelViewTpaReportService hotelViewTpaReportService =
        new HotelViewTpaReportService(mockGoogleOAuthService, dr);

HotelViewTpaReportService 的构造函数调用 superpublic HotelViewTpaReportService(GoogleOAuthService googleOAuthService, DownloadRequest downloadRequest) throws Exception { super(googleOAuthService, downloadRequest);

然后超级 class 构造函数尝试验证 googleOAuthService.authenticateServiceAccount。它应该在这一点上 return 模拟 mockGoogleCredentials 因为我们已经写了 Mockito.when(mockGoogleOAuthService.authenticateServiceAccount(secretJson, SERVICE_ACCOUNT_SCOPES)).thenReturn(mockGoogleCredentials);。但它不会并尝试进行身份验证。

// Super Class Constructor
public AbstractTpaReportService(GoogleOAuthService googleOAuthService, DownloadRequest downloadRequest) throws Exception {
    this.downloadRequest = downloadRequest;

    this.tpaReportConfig = new TPAReportConfig(downloadRequest);

    final byte[] secretJson = Base64.getDecoder().decode(getRequiredOption(downloadRequest, "secretJson"));

    this.googleCredentials = googleOAuthService.authenticateServiceAccount(secretJson, SERVICE_ACCOUNT_SCOPES);
}

我是 Java 的新手,我是从 python 和 nodejs 迁移过来的。

感谢任何帮助。

在 Mockito 中存在不同类型的 mock/stub 对象:

Mockito 的模拟对象

Baeldung 教程:Mockito - Using Spies, 5. Mock vs Spy,简单区分两者:

  • Mock: 没有行为对象,主要是 returning null, empty or false

    When Mockito creates a mock – it does so from the Class of a Type, not from an actual instance. The mock simply creates a bare-bones shell instance of the Class, entirely instrumented to track interactions with it.

  • Spy: object using existing behavior, 主要用于验证

    On the other hand, the spy will wrap an existing instance. It will still behave in the same way as the normal instance – the only difference is that it will also be instrumented to track all the interactions with it.

仅使用 Mock

有几件事,你应该做不同的和更简单的:

  • 您已经创建了 Mock 个对象。不要用 Spy 个对象覆盖它们。
  • 在定义模拟 return
  • 时,使用 any(),更好地键入 ArgumentMatchers.any(Your.class) 或类似于 argument-matcher
// Arrange
  GoogleOAuthService mockAuthService = Mockito.mock(GoogleOAuthService.class);
  // mockGoogleOAuthService = Mockito.spy(mockGoogleOAuthService);

  GoogleCredentials mockCredentials = Mockito.mock(GoogleCredentials.class);
  // mockGoogleCredentials = Mockito.spy(mockGoogleCredentials);

  // defining a mocked response, using `any()` as argument-matcher
  Mockito.when(mockService.authenticateServiceAccount(any(), any()).thenReturn(mockCredentials);

  // injecting the mock
  final HotelViewTpaReportService hotelViewTpaReportService =
 new HotelViewTpaReportService(mockAuthService, dr);

// Act

高级 Mockito 用法

由于使用 mocks 应该可以简化您的测试代码,因此使用 Mockito(在 JUnit 中)测试有更优雅或更理想的方法 - 将其与“pythonic”进行比较:

  • 使用注释@Mock@Spy@InjectMocks)来声明和实例化并注入模拟
  • 使用 static imports 以最易读的方式缩短 Mockito 辅助方法的使用

您的代码可能如下所示:

// import some useful static methods
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;

class MyTest {

  // first creating the mocks
  @Mock
  final GoogleOAuthService mockAuthService;
  @Mock
  final GoogleCredentials mockCredentials
  
  // then injecting the mocks
  @InjectMocks
  final HotelViewTpaReportService hotelViewTpaReportService;

  @BeforeEach
  public void beforeEach() {
    MockitoAnnotations.initMocks(this);
    // could also define mock-behavior here, using `when(mockedObject. ..)`
  }

  @Test
  public void testAuthentication() {
    // Arrange
    // defining a mocked response specific for your test
    when(mockService.authenticateServiceAccount(any(), any()).thenReturn(mockCredentials);

    // Act
    // ... your code here

    // Assert
    // ... your code here
  }

另请参阅: