スタブ API を使用したモックフレームワークの作成
実行時に Apex クラスの匿名サブクラスとして作成されるスタブオブジェクトの動作を定義できます。スタブ API は System.StubProvider インターフェースと System.Test.createStub() メソッドから構成されます。
スタブ API がどのように機能するかを示す例を見てみましょう。この例は、モックフレームワークの幅広い用途を示すものではありません。Apex スタブ API の使用上のしくみに焦点を絞るために、意図的に簡潔に記述されています。
次のクラスの書式設定メソッドをテストするとします。
1public class DateFormatter {
2 // Method to test
3 public String getFormattedDate(DateHelper helper) {
4 return 'Today\'s date is ' + helper.getTodaysDate();
5 }
6}通常、このメソッドを呼び出すときは、今日の日付を返すメソッドがあるヘルパークラスを渡します。
1public class DateHelper {
2 // Method to stub
3 public String getTodaysDate() {
4 return Date.today().format();
5 }
6}次のコードは、メソッドを呼び出します。
1DateFormatter df = new DateFormatter();
2DateHelper dh = new DateHelper();
3String dateStr = df.getFormattedDate(dh);テストでは、getFormattedDate() メソッドを切り離して、書式設定が適切に機能していることを確認したいと考えています。getTodaysDate() メソッドの戻り値は通常、日によって異なります。ただし、この例では、テストを書式設定に限定する予測可能な定数値を返すようにします。ここでは、メソッドが定数値を返すクラスの「疑似」バージョンを記述するのではなく、クラスのスタブバージョンを作成します。実行時にスタブオブジェクトが動的に作成され、そのメソッドの「スタブ」動作を指定することができます。
- System.StubProvider インターフェースを実装してスタブクラスの動作を定義します。
- System.Test.createStub() メソッドを使用してスタブオブジェクトをインスタンス化します。
- テストクラス��からスタブオブジェクトの該当するメソッドを呼び出します。
StubProvider インターフェースの実装
以下は StubProvider インターフェースの実装です。
1@isTest
2public class MockProvider implements System.StubProvider {
3
4 public Object handleMethodCall(Object stubbedObject, String stubbedMethodName,
5 Type returnType, List<Type> listOfParamTypes, List<String> listOfParamNames,
6 List<Object> listOfArgs) {
7
8 // The following debug statements show an example of logging
9 // the invocation of a mocked method.
10
11 // You can use the method name and return type to determine which method was called.
12 System.debug('Name of stubbed method: ' + stubbedMethodName);
13 System.debug('Return type of stubbed method: ' + returnType.getName());
14
15 // You can also use the parameter names and types to determine which method
16 // was called.
17 for (integer i =0; i < listOfParamNames.size(); i++) {
18 System.debug('parameter name: ' + listOfParamNames.get(i));
19 System.debug(' parameter type: ' + listOfParamTypes.get(i).getName());
20 }
21
22 // This shows the actual parameter values passed into the stubbed method at runtime.
23 System.debug('number of parameters passed into the mocked call: ' +
24 listOfArgs.size());
25 System.debug('parameter(s) sent into the mocked call: ' + listOfArgs);
26
27 // This is a very simple mock provider that returns a hard-coded value
28 // based on the return type of the invoked.
29 if (returnType.getName() == 'String')
30 return '8/8/2016';
31 else
32 return null;
33 }
34}StubProvider はコールバックインターフェースで、実装を必要とする handleMethodCall() という 1 つのメソッドを指定します。スタブメソッドがコールされると、handleMethodCall() がコールされます。このメソッドのスタブクラスの動作を定義します。このメソッドには次のパラメータがあります。
- stubbedObject: スタブオブジェクト
- stubbedMethodName: 呼び出されるメソッドの名前
- returnType: 呼び出されるメソッドの戻り値の型
- listOfParamTypes: 呼び出されるメソッドのパラメータの型のリスト
- listOfParamNames: 呼び出されるメソッドのパラメータ名のリスト
- listOfArgs: 実行時にこのメソッドに渡される実際の引数値
これらのパラメータを使用して、クラスのどのメソッドがコールされたのかを判断し、続いて各メソッドの動作を定義できます。この場合は、メソッドの戻り値の型を特定して、ハードコードされた値を返します。
クラスのスタブバージョンのインスタンス化
次のステップは、クラスのスタブバージョンをインスタンス化することです。次のユーティリティクラスは、擬似オブジェクトとして使用できるスタブオブジェクトを返します。
1public class MockUtil {
2 private MockUtil(){}
3
4 public static MockProvider getInstance() {
5 return new MockProvider();
6 }
7
8 public static Object createMock(Type typeToMock) {
9 // Invoke the stub API and pass it our mock provider to create a
10 // mock class of typeToMock.
11 return Test.createStub(typeToMock, MockUtil.getInstance());
12 }
13}このクラスには、Test.createStub() メソッドを呼び出す createMock() メソッドが含まれます。createStub() メソッドは、Apex クラス種別と、以前作成した StubProvider インターフェースのインスタンスを取ります。そして、テストで使用できるスタブオブジェクトを返します。
スタブメソッドの呼び出し
最後に、テストクラス内からスタブクラスの該当するメソッドを呼び出します。
1@isTest
2public class DateFormatterTest {
3 @isTest
4 public static void testGetFormattedDate() {
5 // Create a mock version of the DateHelper class.
6 DateHelper mockDH = (DateHelper)MockUtil.createMock(DateHelper.class);
7 DateFormatter df = new DateFormatter();
8
9 // Use the mocked object in the test.
10 System.assertEquals('Today\'s date is 8/8/2016', df.getFormattedDate(mockDH));
11 }
12}このテストでは、createMock() メソッドをコールして、DateHelper クラスのスタブバージョンを作成します。続いて、スタブオブジェクトで getTodaysDate() メソッドを呼び出すことができます。このメソッドはハードコードされた日付を返します。ハードコードされたこの日付を使用すれば、getFormattedDate() メソッドの動作を切り離してテストできます。
Apex スタブ API の制限事項
Apex スタブ API を操作するときは次の点に注意してください。
- 模造されるオブジェクトは、Test.createStub() メソッドへのコールと同じ名前空間にある必要があります。ただし、StubProvider インターフェースの実装は別の名前空間でも構いません。
- 次の Apex 要素は模造できません。
- 静的メソッド (future メソッドを含む)
- 非公開メソッド
- プロパティ (getter および setter)
- トリガ
- 内部クラス
- システム型
- Batchable インターフェースを実装するクラス
- 非公開コンストラクタのみを持つクラス
- 戻り値の型またはパラメータの型としてイテレータは使用できません。