Apexバッチのテストクラスについて

スポンサーリンク

テストコードの書き方も意外と出題される

今回のテーマはテストクラス。
試験でも結構出題されるところなので、押さえておきましょう!
上級試験なので、スタンダードなApexテスト意外にも特殊なケースでのテストクラスについても書き方を留意する必要があります。

今回は手始めにバッチクラスのテストコードの書き方について。
業務上でバッチ処理を書いている人も多いのではないでしょうか?
何となく身についているところもあるかと思いますので、今一度整理してみましょう。

バッチクラスのテストクラスの書き方

まずは、以下バッチクラスに対して、テストコードを記述します。
今回は以前に登場したDatabase.Statefulインタフェースの解説で使用したコードを使用します。

やはりエコの時代、ソースコードも再利用しなければ。
本当はまた新たに書き直すのが面倒だっただけなんだけどね。

一応同じものだけど、ソースを載せておきますね。
BookBatch.cls

public class BookBatch implements Database.Batchable<sObject>, Database.Stateful{
    // Statefulで値を確認するための変数
    public integer Summary;

    public BookBatch(){
        Summary = 0;
    }

    public Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator('Select Id From Book__c');
    }
   
    public void execute(Database.BatchableContext BC, List<scope>){
        for(sObject s : scope){
            // execute内でメンバ変数を更新
            Summary = Summary + 1;
        }
    }

    public void finish(Database.BatchableContext BC){
        System.debug(Summary);
    }
}

そして、テストクラスになります。
BookBatchTest.cls

@isTest
private class BookBatchTest {
    @isTest static void test_method_1() {
        List<Book__c> bList = new List<Book__c>();
        for(Integer i =0; i < 10; i++){
            Book__c b = new Book__c(Name='book' + String.valueOf(i));
            bList.add(b);
        }
        insert bList;
        
        Test.startTest();
        BookBatch bc = new BookBatch();
        // テストデータ数<=バッチサイズとなるようにバッチサイズを調整する
        Database.executeBatch(bc, 10);
        Test.stopTest();
    }
}

ポイントは2つ

stratTestとstopTestの間にDatabese.executeBatchを入れる

みなさんご存知の通り、バッチ実行は非同期なので、本来であればテストクラスとは別にプロセスが走ることになります。
stratTestとstopTestで挟み込むことによって、この間は同期をとりますよという意味になっているらしいです

対象データ数がバッチサイズ以下になるようにする

こちらが意外と知られていない点。
バッチはバッチサイズに区切って複数プロセスで実行されるのはご存知でしょう。
テストクラス内で1バッチ分だけは、何とか同期をとってくれるんですが、さすがに2バッチ以上はテストクラス側が待たされてしまい、テストパフォーマンスが低下するので、1回のexecuteが実施されるように調整しないといけません。

なお、対象データ数>バッチサイズにしてしまうと、以下のエラーが起こって怒られます。
(上記テストクラスで、for文の10をそれ以上にすると発生します)

System.UnexpectedException: No more than one executeBatch can be called from within a test method. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.

対象データ数についてはある程度考慮しないといけないので、本番組織の実データを使う、@IsTest(SeeAllData=true)アノテーションでテストした時や、APIバージョンが23以下の古いテストクラスはエラーとならないように注意しましょう

まとめ

  • Test.stratTest()とTest.stopTest()の間にDatabese.executeBatchを実行することで、1回分のexecuteが実施される
  • 対象データ数がバッチサイズより大きいとエラー
  • @IsTest(SeeAllData=true)アノテーションは非推奨

コメント