フィールド履歴トラッキングとテストクラスの実装方法


Salesforce の History オブジェクト は、オブジェクトの履歴データを保持する特別なシステムテーブルです。これらの履歴テーブルは Read-Only(読み取り専用) のため、データの整合性を維持する目的で書き込み操作は制限されています。そのため、独自の履歴追跡メカニズムを実装する必要がある場合があります。

本記事では、フィールド履歴トラッキングのテスト実装や、その課題を解決する方法を紹介します。


1. フィールド履歴トラッキングの仕組み

Salesforceでフィールド履歴トラッキングを有効化すると、変更内容(フィールド、旧値、新値など)が履歴オブジェクト(例: AccountHistory)に自動的に保存されます。しかし、これらの履歴は以下のような特性があります。

  • Read-Only: 手動での書き込みはできない。
  • 遅延書き込み: 同一トランザクション内でクエリを実行すると、まだ履歴データが生成されていない場合があります。

2. 履歴データを取得するテストクラスの問題

以下のようなテストクラスを実行すると、履歴データが取得できずアサーションが失敗する場合があります。

サンプルコード
@isTest
public class AccountTest {
    @isTest
    private static void testOne() {
        Account acc = new Account(Name = 'Hello', Type = 'Other');
        insert acc;

        Test.startTest();
        acc.Type = 'Prospect';
        update acc;
        Test.stopTest();

        AccountHistory[] ah = [
            SELECT AccountId, Field, OldValue, NewValue 
            FROM AccountHistory 
            WHERE AccountId = :acc.Id
        ];
        System.debug('Account History: ' + ah);
        System.assertEquals(1, ah.size()); // アサーションが失敗する
    }
}

この失敗の原因は、履歴データが同一トランザクション中にクエリ可能な状態にならない場合があることです。この制限を回避するための戦略として、テスト環境でモックデータを利用する方法を提案します。


3. モックデータを活用した解決方法

Test.isRunningTest を使用して、テスト中のみモックデータを返すようなユーティリティクラスを作成します。

改良版コード
@isTest
public class AccountHistoryUtil {
    public void processAccountUpdate(Id accountId) {
        Account acc = new Account(Id = accountId, Type = 'Other');
        update acc;
    }

    public AccountHistory[] retrieveAccountHistory(Id accountId) {
        List ah;
        if (Test.isRunningTest()) { // テスト環境の場合、モックデータを返す
            ah = new List{};
            ah.add(new AccountHistory(AccountId = accountId, Field = 'Type'));
        } else {
            ah = [
                SELECT AccountId, Field, OldValue, NewValue 
                FROM AccountHistory 
                WHERE AccountId = :accountId
            ];
        }
        return ah;
    }
    private static void testOne() {
        Account acc = new Account(Name = 'Hello World' + Datetime.now());
        insert acc;

        Test.startTest();
        AccountHistoryUtil accHistClass = new AccountHistoryUtil();
        accHistClass.processAccountUpdate(acc.Id);
        AccountHistory[] accHist = accHistClass.retrieveAccountHistory(acc.Id);
        Test.stopTest();

        System.assertEquals(1, accHist.size()); // モックデータで成功
    }
}

4. 解説

  • Test.isRunningTest を使用
    テスト中に実行されているかどうかを判定する標準メソッドを使用し、テスト用のモックデータを返す処理を実装しました。
  • 履歴データのモック化
    テストクラスで実際の履歴オブジェクトに依存せず、必要なモックデータを生成することで、アサーションの成功率を向上させています。

結論

履歴オブジェクトは強力な監査ツールですが、その特性によりテスト実装に課題が生じる場合があります。本記事で紹介した方法を活用することで、履歴トラッキングのテストにおけるアサーション失敗の問題を回避できるでしょう。ぜひプロジェクトに取り入れて、より堅牢なテストを構築してください!

コメント