モッキート @InjectMocks – 依存関係のインジェクションをモック化
Mockitoの@InjectMocksアノテーションは、アノテーションされたクラスのモックされた依存関係に対してインジェクションを行うことができます。これは、モックしたいクラスに外部の依存関係がある場合に便利です。@Mockまたは@Spyアノテーションを使用して、インジェクトするモックオブジェクトを指定することができます。
モッキート @InjectMocks
モッキートは、指定された順序で3つのアプローチのいずれかを使用して、モックされた依存関係を注入しようとします。
-
- コンストラクタベースのインジェクション – クラスにコンストラクタが定義されている場合、Mockitoは最も大きなコンストラクタを使用して依存関係を注入しようとします。
-
- セッターメソッドベース – コンストラクタが定義されていない場合、Mockitoはセッターメソッドを使用して依存関係を注入しようとします。
- フィールドベース – コンストラクタやフィールドベースのインジェクションが不可能な場合、Mockitoは依存関係をフィールド自体に注入しようとします。
もし一つのマッチングするモックオブジェクトしかない場合、Mockitoはそのオブジェクトを注入します。もし同じクラスの複数のモックオブジェクトがある場合、モックオブジェクト名を使用して依存関係を注入します。
モックの @InjectMocks の例を示します。
依存関係を持つサービスやクラスを作成して、モックの依存関係注入をMockitoで実行する様子を見てみましょう。
package com.scdev.injectmocksservices;
public interface Service {
public boolean send(String msg);
}
package com.scdev.injectmocksservices;
public class EmailService implements Service {
@Override
public boolean send(String msg) {
System.out.println("Sending email");
return true;
}
}
package com.scdev.injectmocksservices;
public class SMSService implements Service {
@Override
public boolean send(String msg) {
System.out.println("Sending SMS");
return true;
}
}
依存関係を持つ App Service クラス
package com.scdev.injectmocksservices;
//For Constructor Based @InjectMocks injection
public class AppServices {
private EmailService emailService;
private SMSService smsService;
public AppServices(EmailService emailService, SMSService smsService) {
this.emailService = emailService;
this.smsService = smsService;
}
public boolean sendSMS(String msg) {
return smsService.send(msg);
}
public boolean sendEmail(String msg) {
return emailService.send(msg);
}
}
package com.scdev.injectmocksservices;
//For Property Setter Based @InjectMocks injection
public class AppServices1 {
private EmailService emailService;
private SMSService smsService;
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
public void setSmsService(SMSService smsService) {
this.smsService = smsService;
}
public boolean sendSMS(String msg) {
return smsService.send(msg);
}
public boolean sendEmail(String msg) {
return emailService.send(msg);
}
}
package com.scdev.injectmocksservices;
//For Field Based @InjectMocks injection
public class AppServices2 {
private EmailService emailService;
private SMSService smsService;
public boolean sendSMS(String msg) {
return smsService.send(msg);
}
public boolean sendEmail(String msg) {
return emailService.send(msg);
}
}
@InjectMocksコンストラクターインジェクションの例
package com.scdev.mockito.injectmocks;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import com.scdev.injectmocksservices.AppServices;
import com.scdev.injectmocksservices.AppServices1;
import com.scdev.injectmocksservices.AppServices2;
import com.scdev.injectmocksservices.EmailService;
import com.scdev.injectmocksservices.SMSService;
class MockitoInjectMocksExamples extends BaseTestCase {
@Mock EmailService emailService;
@Mock SMSService smsService;
@InjectMocks AppServices appServicesConstructorInjectionMock;
@InjectMocks AppServices1 appServicesSetterInjectionMock;
@InjectMocks AppServices2 appServicesFieldInjectionMock;
@Test
void test_constructor_injection_mock() {
when(appServicesConstructorInjectionMock.sendEmail("Email")).thenReturn(true);
when(appServicesConstructorInjectionMock.sendSMS(anyString())).thenReturn(true);
assertTrue(appServicesConstructorInjectionMock.sendEmail("Email"));
assertFalse(appServicesConstructorInjectionMock.sendEmail("Unstubbed Email"));
assertTrue(appServicesConstructorInjectionMock.sendSMS("SMS"));
}
}
私のテストクラスがBaseTestCaseを拡張しているのに気付きましたか。これはテストの前にMockitoのモックを初期化するためです。以下にクラスのコードがあります。
package com.scdev.mockito.injectmocks;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.MockitoAnnotations;
class BaseTestCase {
@BeforeEach
void init_mocks() {
MockitoAnnotations.initMocks(this);
}
}
この場合、MockitoAnnotations.initMocks(this)を呼び出さなければ、NullPointerExceptionが発生します。また、テストケースを実行するためにJUnit 5を使用しています。それに慣れていない場合は、JUnit 5のチュートリアルを参照してください。
@InjectMocksアノテーションを使用したセッターメソッドのインジェクションの例
@Test
void test_setter_injection_mock() {
when(appServicesSetterInjectionMock.sendEmail("New Email")).thenReturn(true);
when(appServicesSetterInjectionMock.sendSMS(anyString())).thenReturn(true);
assertTrue(appServicesSetterInjectionMock.sendEmail("New Email"));
assertFalse(appServicesSetterInjectionMock.sendEmail("Unstubbed Email"));
assertTrue(appServicesSetterInjectionMock.sendSMS("SMS"));
}
@InjectMocksを使用したフィールドベースのインジェクションの例
@Test
void test_field_injection_mock() {
when(appServicesFieldInjectionMock.sendEmail(anyString())).thenReturn(true);
when(appServicesFieldInjectionMock.sendSMS(anyString())).thenReturn(true);
assertTrue(appServicesFieldInjectionMock.sendEmail("Email"));
assertTrue(appServicesFieldInjectionMock.sendEmail("New Email"));
assertTrue(appServicesFieldInjectionMock.sendSMS("SMS"));
}
私たちのGitHubリポジトリから、完全なコードとより多くのモックitoの例を確認することができます。
参照:APIドキュメント