モキートのチュートリアル
モッキートは、Javaベースのモッキングフレームワークであり、JUnitやTestNGなどの他のテストフレームワークと組み合わせて使用されます。内部的にはJavaの反射APIを使用し、サービスのオブジェクトを作成することができます。モックオブジェクトは、ダミーデータを返し、外部の依存関係を避けます。外部の依存関係をモック化し、テスト対象のコードに適用することで、テストの開発を簡素化する役割を果たします。
モキートのチュートリアル
モキートのチュートリアルでは、JUnit 5を使用していくつかのサービスをモックします。
モキートのMaven依存関係
プロジェクトでMockitoベースのテストケースを実装するためには、プロジェクトのpom.xmlファイルに以下の依存関係を追加してください。
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
JUnit 5を使用する場合は、mockito-junit-jupiterが必要ですが、JUnit 4やTestNGなどの他のテストフレームワークを使用している場合は、この依存関係を削除し、mockito-coreの依存関係のみを含めてください。
モッキトのモック作成
Mockitoフレームワークを使用することで、@Mockアノテーションやmock()静的メソッドのいずれかを使ってモックオブジェクトを作成することができます。
モックオブジェクトを作成するためのMockitoのmock()メソッド。
以下の例は、mock()メソッドの使用方法を示しています。
package com.scdev.mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import com.scdev.AddService;
import com.scdev.CalcService;
public class CalcService1Test {
@Test
void testCalc() {
System.out.println("**--- Test testCalc executed ---**");
AddService addService;
CalcService calcService;
addService = Mockito.mock(AddService.class);
calcService = new CalcService(addService);
int num1 = 11;
int num2 = 12;
int expected = 23;
when(addService.add(num1, num2)).thenReturn(expected);
int actual = calcService.calc(num1, num2);
assertEquals(expected, actual);
}
}
上記の例では、CalcServiceをテストしています。Mockito.mock()メソッドは、AddServiceクラスのモックオブジェクトを作成するために使用されます。
モッキートのモックアノテーション
以下の例は、@Mock注釈の使用法を示しています。
package com.scdev.mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.scdev.AddService;
import com.scdev.CalcService;
public class CalcService2Test {
CalcService calcService;
@Mock
AddService addService;
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testCalc() {
System.out.println("**--- Test testCalc executed ---**");
calcService = new CalcService(addService);
int num1 = 11;
int num2 = 12;
int expected = 23;
when(addService.add(num1, num2)).thenReturn(expected);
int actual = calcService.calc(num1, num2);
assertEquals(expected, actual);
}
}
注意してほしいのは、@Mock、@Spy、@Captor、または@InjectMocksで注釈付けされたオブジェクトを初期化するためにMockitoAnnotations.initMocks(this)を呼び出す必要があるということです。
モッキートの振る舞いの確認
モックされたクラスに動作を追加するために、when()とthenReturn()関数を使用します。これは、モックオブジェクト(addService)が(addメソッドに(num1、num2)パラメータを使用して呼び出される場合、expected変数に格納された値を返すということです。CalcServiceクラスの形式は以下のようになります。
public class CalcService {
private AddService addService;
public CalcService(AddService addService) {
this.addService = addService;
}
public int calc(int num1, int num2) {
System.out.println("**--- CalcService calc executed ---**");
return addService.add(num1, num2);
}
}
CalcServiceクラスはAddServiceクラスに依存しています。CalcServiceクラスは、AddServiceクラスのaddメソッドを使用して操作を行います。CalcServiceクラスの単体テストのために、AddServiceインスタンスをモック化する必要がありました。以下はAddServiceの見た目です。
public interface AddService {
public int add(int num1, int num2);
}
public class AddServiceImpl implements AddService {
@Override
public int add(int num1, int num2) {
System.out.println("**--- AddServiceImpl add executed ---**");
return num1 + num2;
}
}
モッキートの相互作用を検証する。
モックオブジェクトへのメソッド呼び出しとそのパラメータは、Mockitoフレームワークが追跡します。モックオブジェクトのMockito verify()メソッドは、特定のパラメータでメソッドが呼び出されたことを検証します。また、正確な回数、指定された回数以上、指定された回数未満など、呼び出し回数のロジックを指定することもできます。呼び出し回数のロジックにはVerificationModeFactoryを使用できます。Mockito verify()メソッドは、メソッドが適切なパラメータで呼び出されたかどうかをチェックします。ただし、アサートメソッドのようにメソッド呼び出しの結果をチェックしません。以下の例は、verify()メソッドの使用方法を示しています。
package com.scdev.mockito;
import static org.mockito.Mockito.verify;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.internal.verification.VerificationModeFactory;
public class VerifyInteractionTest {
@Test
public void testMethod() {
@SuppressWarnings("unchecked")
List<String> mockedList = Mockito.mock(List.class);
mockedList.add("first-element");
mockedList.add("second-element");
mockedList.add("third-element");
mockedList.add("third-element");
mockedList.clear();
verify(mockedList).add("first-element");
verify(mockedList).add("second-element");
verify(mockedList, VerificationModeFactory.times(2)).add("third-element");
verify(mockedList).clear();
}
}
モッキートを用いた具象クラスのスタブ化
when() – thenReturn()関数を使用することで、具体的な実装クラスやコレクションの単一の要素をスタブ化することができます。スタブ化されていない要素にはnullが含まれます。
package com.scdev.mockito;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MockSingleElementTest {
@SuppressWarnings("unchecked")
@Test
public void testMethod() {
ArrayList mockedList = mock(ArrayList.class);
when(mockedList.get(0)).thenReturn("first-element");
System.out.println(mockedList.get(0));
assertEquals("first-element", mockedList.get(0));
// "null" gets printed as get(1) is not stubbed
System.out.println(mockedList.get(1));
}
}
モッキートのスパイ機能
スパイオブジェクトのメソッドを呼び出す場合、事前に定義された振る舞いがなければ実際のメソッドが呼び出されます。spy を使用することで when() – theReturn() 関数を使用して振る舞いを定義したり、実際の実装を呼び出すことができます。
package com.scdev.mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
public class MockitoSpyTest {
@Test
public void testMethod() {
List<String> list = new ArrayList<>();
List<String> listSpy = spy(list);
listSpy.add("first-element");
System.out.println(listSpy.get(0));
assertEquals("first-element", listSpy.get(0));
when(listSpy.get(0)).thenReturn("second-element");
System.out.println(listSpy.get(0));
assertEquals("second-element", listSpy.get(0));
}
}
結論
モックのフレームワークとして人気のあるMockitoは、Javaの単体テストにおいて依存関係を簡単にモック化することができます。Mockitoのコーディングスタイルは、JUnitやTestNGフレームワークに似ており、学習コストが非常に小さいです。
私たちのGitHubリポジトリから完全なプロジェクトのコードをダウンロードすることができます。