SalesforceにおけるWebサービスコールアウトのテスト完全ガイド


本記事では、外部APIへの依存を排除し、安定したテスト実行を実現するための主要な手法をまとめています。HttpCalloutMockやStaticResourceCalloutMock、WebServiceMockの使い分けから、Test.startTest()/Test.stopTest()、Limitsメソッドによるガバナ制限管理まで、Salesforceが公式にサポートする機能を網羅的に解説します。

🔍 Webサービスコールアウトの概要

  • RESTコールアウト:HttpRequest/HttpResponseを使った JSON または XML ベースの通信

  • SOAPコールアウト:WSDLから自動生成された Apex クラスを利用するXMLベースの通信

  • 同期・非同期の両方で実行可能で、バッチ処理やトリガー内でも利用されます


⚠️ テスト時の主な課題

  • 外部システム依存:ダウンや遅延でテストが不安定に

  • APIレート制限:同期Apexではコールアウト上限が100回/トランザクション

  • データ変動:外部データの更新でテスト結果が再現できない

  • 実行時間増加:API応答遅延がCI/CDの実行時間を延長


🛠 テスト手法

1️⃣ HttpCalloutMock インターフェース

  1. HttpCalloutMockを実装し、respondメソッドで擬似HttpResponseを返却

  2. テスト内でTest.setMock(HttpCalloutMock.class, new MockClass()) を呼び出し、任意のレスポンスをシミュレート

@isTest
private class WeatherTest {
    class MockWeather implements HttpCalloutMock {
        public HttpResponse respond(HttpRequest req) {
            HttpResponse res = new HttpResponse();
            res.setStatusCode(200);
            res.setBody('{"temp":"30°C","cond":"Sunny"}');
            return res;
        }
    }
    @isTest static void testWeather() {
        Test.setMock(HttpCalloutMock.class, new MockWeather());
        String r = WeatherService.getWeather('Tokyo');
        System.assert(r.contains('30°C'));
    }
}

2️⃣ StaticResourceCalloutMock の活用

  1. 静的リソースにJSON/XMLを保存してテスト用レスポンスを管理

  2. StaticResourceCalloutMock('ResourceName', 200) で自動的にボディをロード

@isTest
private class WeatherTestSR {
    @isTest static void testWithSR() {
        StaticResourceCalloutMock mock = new StaticResourceCalloutMock('MockWeather', 200);
        Test.setMock(HttpCalloutMock.class, mock);
        String res = WeatherService.getWeather('London');
        System.assert(res.contains('28°C'));
    }
}

3️⃣ WebServiceMock を使ったSOAPコールアウト

  1. WSDLから自動生成されたStubクラス向けにWebServiceMockを実装

  2. Test.setMock(WebServiceMock.class, new MockSoap()) でテスト時にSOAP呼び出しを差し替え

@isTest
private class SoapTest {
    class MockSoap implements WebServiceMock {
        public void doInvoke(..., Object response, ...) {
            // responseオブジェクトにテスト用の値をセット
        }
    }
    @isTest static void testSoapCallout() {
        Test.setMock(WebServiceMock.class, new MockSoap());
        MySoapStub.Result r = MySoapStub.callMyService(...);
        System.assertEquals('OK', r.getStatus());
    }
}

⏱ ガバナ制限の管理

▶️ Test.startTest()/Test.stopTest()

  • Test.startTest() から Test.stopTest() の間で新しいガバナ制限枠が与えられる

  • 非同期処理(@future, Queueable, Batch)を同期的に完了させる

Test.setMock(HttpCalloutMock.class, new MockWeather());
Test.startTest();
WeatherService.calloutMethod();
Test.stopTest();

▶️ Limits メソッドで回数チェック

  • Limits.getCallouts():現在発行済みのコールアウト回数を取得

  • Limits.getLimitCallouts():トランザクションあたり最大コールアウト回数(100)を取得

Integer before = Limits.getCallouts();
WeatherService.calloutMethod();
Integer after = Limits.getCallouts();
System.assertEquals(before + 1, after);
System.assert(after <= Limits.getLimitCallouts());

✨ まとめ

  • HttpCalloutMock / StaticResourceCalloutMock / WebServiceMock を適切に使い分けて外部依存を排除

  • Test.startTest()/stopTest() でガバナ制限をリセットし、非同期処理を同期テストに組み込む

  • Limitsメソッド でコールアウト回数をチェックし、安全な設計を担保

これらの手法を導入することで、外部システムの状況に左右されない、再現性と安定性の高いテストを実現できます。プロジェクトの品質向上と開発効率アップにぜひお役立てください!

コメント