カスタムメタデータのテストについて調べてみた

カスタムメタデータの環境に依存しないテストコードの書き方について調べてみました。
2023.03.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは!Salesforceエンジニアの にしたに です。

みなさん、カスタムメタデータは使っていますか?(挨拶)

カスタムメタデータはオブジェクトのように設定データを利用できる便利な機能ですが、
テストコードからテストデータを作成できず、環境に依存してしまう点が気になっていました。

今回の記事では、カスタムメタデータのテストコードを環境に依存しない形で書けないか調べた結果を共有したいと思います。

この記事の対象者

  • カスタムメタデータを利用しているSalesforceエンジニア
  • 環境に依存しないテストコードを書きたい方

前提

カスタムメタデータを使う際、テストコードは必要不可欠です。
例として以下のSiteUrl__mdtカスタムメタデータを作成します。

表示ラベル API参照名 データ型
サイト名 SiteName__c テキスト
URL Url__c URL

サイト名に対応するURLを持っている簡素なカスタムメタデータです。
このメタデータを活用する以下のコードがあったとします。

public with sharing class SiteUrlMetadata {
    /**
     * サイト名に対応したURLを返す
     * 見つからなかった場合、nullを返す
     * @param siteName サイト名
     * @return サイト名に対応したURL 見つからなかった場合Null
     */
    public static String getUrl(String siteName) {
        // カスタムメタデータを全件取得
        List<SiteUrl__mdt> siteUrlList = SiteUrl__mdt.getAll().values();

        for (SiteUrl__mdt siteUrl : siteUrlList) {
            // サイト名が一致した場合、URLを返す
            if (siteUrl.SiteName__c == siteName) {
                return siteUrl.Url__c;
            }
        }
        return null;
    }
}

テストコードを以下のように書き、実行します。

@IsTest
public with sharing class SiteUrlMetadataTest {
    @IsTest static void test_getUrl_success() {
        String url = SiteUrlMetadata.getUrl('Test Site Name');
        System.assertEquals('http://www.example.com', url);
    }
}

エラーメッセージが出て失敗しました。
System.AssertException: Assertion Failed: Expected: http://www.example.com, Actual: null

まだカスタムメタデータには何もデータを入れてないため、nullが返って来ています。

ここでカスタムメタデータに正しいデータを入れることで、テストコードは問題なく動作します。
ですがその場合、テストコードが環境のデータに依存することになってしまいます。

今回の例では特に問題ないように見えますが、環境ごとに違った値を設定したい場合に適切な状態ではなくなります。

そこでこの記事では、環境に依存しないカスタムメタデータのテストコードについて考えてみます。

環境に依存しないテストコード

先ほどのテストコードを少し変え、カスタムメタデータのテストデータを作成するようにしてみます。

@IsTest
public with sharing class SiteUrlMetadataTest {
    @IsTest static void test_getUrl_success() {
        // カスタムメタデータのテストデータを作成する
        insert new SiteUrl__mdt(SiteName__c = 'Test Site Name', Url__c = 'http://www.example.com');

        String url = SiteUrlMetadata.getUrl('Test Site Name');
        System.assertEquals('http://www.example.com', url);
    }
}

テスト実行前のdeployで以下のエラーになりました。
DML operation Insert not allowed on SiteUrl__mdt

カスタムメタデータのDML操作は許可されていないため、テストデータを作成することは出来ません。

そこで発想を変え、カスタムメタデータのDAOクラスを定義し、getterとsetterを用意することで
テストクラスからテストデータを設定出来るような形にしてみました。

/**
 * カスタムメタデータのDAO(Data Access Object)クラス
 * 基本的にカスタムメタデータはこのクラスから取得する
 * (テストクラスでテストデータを作成するため)
 */
public with sharing class CustomMetadataDAO {
    /**
     * SiteUrl__mdtの全件を返す
     * @return Map<String, SiteUrl__mdt>
     */
    public static Map<String, SiteUrl__mdt> siteUrlMap {
        get{
            if(siteUrlMap == null) {
                // getAll()はすべての項目を返す
                // ただし、各項目の255文字以降は切り捨てられるので注意。ロングテキスト項目などある場合、SOQLを使うこと。
                siteUrlMap = SiteUrl__mdt.getAll();
            }
            return siteUrlMap;
        }
        set;
    }
}

このようにsetも出来る形にすることで、テストコードからテストデータを設定することが可能になります。


DAOを使うよう修正したコードが以下になります。

public with sharing class SiteUrlMetadata {
    /**
     * サイト名に対応したURLを返す
     * 見つからなかった場合、nullを返す
     * @param siteName サイト名
     * @return サイト名に対応したURL 見つからなかった場合Null
     */
    public static String getUrl(String siteName) {
        // カスタムメタデータを全件取得
        List<SiteUrl__mdt> siteUrlList = CustomMetadataDAO.siteUrlMap.values();

        for (SiteUrl__mdt siteUrl : siteUrlList) {
            // サイト名が一致した場合、URLを返す
            if (siteUrl.SiteName__c == siteName) {
                return siteUrl.Url__c;
            }
        }
        return null;
    }
}


テストコードからテストデータを設定するため、以下のようにコードを修正します。

@IsTest
public with sharing class SiteUrlMetadataTest {
    @IsTest static void test_getUrl_success() {

        // テストデータを設定
        CustomMetadataDAO.siteUrlMap = new Map<String, SiteUrl__mdt>{
            'TEST0001' => new SiteUrl__mdt(SiteName__c = 'Test Site Name', Url__c = 'http://www.example.com/test1'),
            'TEST0002' => new SiteUrl__mdt(SiteName__c = 'Test Site Name2', Url__c = 'http://www.example.com/test2')
        };

        String url = SiteUrlMetadata.getUrl('Test Site Name');
        System.assertEquals('http://www.example.com/test1', url);
    }
}

テストを実行すると、無事テストが成功しました。
SiteUrlMetadataTest.test_getUrl_success Pass

最後に

今回は環境に依存しないカスタムメタデータのテストコードをご紹介しました。
カスタムメタデータはオブジェクトのように設定データを利用できる便利な機能ですが、テストコードが環境に依存してしまう点が気になっていました。
この記事の内容でその点が解消されたかなと思います。

どなたかの参考になれば幸いです。