【第二世代管理パッケージ(2GP)】unpackagedMetadataの使い方

2GP連載記事の第4弾です。Spring ’21にて、「パッケージバージョン作成テストでのパッケージ化されていないメタデータの指定 」が正式リリースされました。今回はパッケージのプロジェクト設定ファイルに追加されたパラメータ(unpackagedMetadata)がどのような機能なのか解説します。

今までの記事は[連載]第二世代管理パッケージ(2GP)をご覧ください。

この機能を使うとできること

この機能は、パッケージに含めたくない(もしくは含められない)メタデータが必要なApexテストを書く際に利用できる仕組みです。

参照: パッケージバージョン作成テストでのパッケージ化されていないメタデータまたは Apex アクセス権の指定

この機能の概要は以下のようにまとめられます。図と合わせてご覧ください。

  • パッケージに含めないメタデータのパスをsfdx-project.jsonunpackagedMetadataで指定する。
  • パッケージに含めないメタデータを使用するApexテストもunpackagedMetadataのパスに入れる。
  • unpackagedMetadata内のApexテストもパッケージのコードカバー率の計算に含まれる。
  • unpackagedMetadata内のメタデータは登録者組織にはインストールされない。

特にコードカバー率についてはドキュメントに明記はありませんでしたが、検証したところunpackagedMetadataに含まれるApexテストと合わせてパッケージに必要な75%のコードカバー率を超えていれば問題ないことが確認できました。それを考えると、Apexテストは全てunpackagedMetadataに配置する方がApexテストクラスの配置場所に悩まなくてよいかもしれません

利用シーン

この機能はどんなケースで使えるのでしょうか。例えば以下のような機能を持つAppExchangeアプリを考えてみましょう。

  • 外部サービスのAPIでデータを取得し、Salesforceのオブジェクトにデータを同期する。
  • どのオブジェクトのどの項目に同期するかはユーザがマッピング設定できる。

外部サービスとの連携アプリではありがちな機能だと思います。このような機能のApexテストを書く場合、可能であれば様々なオブジェクト/項目定義のパターンでテストを書きたいものです。しかし、パッケージ内にテストに使用するカスタムオブジェクト定義を入れるわけにはいきません。こんなときにunpackagedMetadataを利用すると、テストしたいカスタムオブジェクト/項目をパッケージに入れずにテストのときにだけ使用することができます。

また、パッケージのリリースでは75%以上のコードカバー率が必要ですが、unpackagedMetadataで指定したパスに入れたApexテストもきちんとパッケージのコードカバー率には含まれます。したがって、上記のような汎用的な機能が多くパッケージ内でできるテストだけではコードカバー率75%を超えるのが難しいケースには非常に役に立つでしょう。

第一世代管理パッケージ(1GP)でも実は同じようなことは実現できていました。上のケースの場合、1GPでは「パッケージ開発組織にカスタム項目/オブジェクトを定義するがパッケージに入れない」という方法で似たようなことはできました。1GPではApexテストはパッケージ作成時にパッケージ開発組織で行われるため、Apexテストで使用するリソースはパッケージ内になくてもパッケージ開発組織にあればいいのです。ただし、1GPではパッケージ開発組織にパッケージに入れるメタデータと入れないメタデータが混在してしまい管理が煩雑でした。

unpacakgedMetadataを利用すると、2GPの利点であるソースドリブンなパッケージ開発を維持しつつ、上記のようなパッケージに入れたくないメタデータを使用したApexテストの実装を可能になります

使い方

sfdxプロジェクトを作るとパッケージディレクトリが一つ作成されますが、まずこちらをもう一つ作る必要があります。

以降の例では以下のディレクトリ構成を想定します。

.
├── config
├── sfdx-src
│ ├── managed <パッケージに入れるメタデータ>
│ └── unmanaged <パッケージに入れないメタデータ>
└── sfdx-project.json

このディレクトリ構成でsfdx-project.jsonに以下のように設定します。

"packageDirectories": [
  {
    "path": "sfdx-src/managed",
    "default": true,
    "package": "UnpackagedMetadata Example App",
    "versionName": "ver 0.1",
    "versionNumber": "0.1.0.NEXT",
    "unpackagedMetadata": {
      "path": "sfdx-src/unmanaged"
    },
    "apexTestAccess": {
      "permissionSets": [
          "UnmanagedTestUser"
      ]
    }
  },
  {
    "path": "sfdx-src/unmanaged",
    "default": false
  },
]

太字斜体の箇所がunpackagedMetadataを利用するために追加した設定です。
パッケージに入れたくないメタデータのあるパスをpackageDirectoriesのデフォルトパスのunpackagedMetadataに設定することに加え、“default“: falseとしてパスを設定する必要があります。

apexTestAccessの設定はオプションですが、Apexテストの実行ユーザに権限セットや権限セットライセンスが必要な場合に設定します。Apexテスト内でユーザを作成して権限セットを付与してSystem.runAsをすることで同じことが可能ですが、apexTestAccessを使用するとそのようなテストを簡易な設定で書くことが可能になります。ただし、権限セットがある/ない場合/権限セットAが付与された場合/Bが付与された場合、のようにさまざまなパターンをテストする場合は結局System.runAsを使用する必要があります。

終わりに

AppExchangeアプリの開発では、ユーザの定義したカスタムオブジェクトに依存するロジックが必要となるケースが少なくありません。unpackagedMetadataがリリースされたことで、パッケージに含めないメタデータを使ったApexテストが書けないという2GPの機能不足が解消され、2GP導入への障壁がまた一つ減りました。

また、今回の検証で判明したunpackagedMetadataのApexテストも含めてコードカバー率が計算されるという事実は、Apexテストクラスのディレクトリ構成に選択肢を一つ加える発見でした。

いかがでしたでしょうか、この記事がAppExchangeアプリを開発しようとされている皆様のお役に立てば幸いです。

ABOUTこの記事をかいた人

株式会社co-meeting代表取締役CEO。カレンダーアプリ「Calsket」のなど複数のAppExchangeアプリを開発。顧問Salesforceプログラマとして他社のAppExchangeアプリ開発にも携わる。SWTT登壇3回、Salesforceハックチャレンジ2014最優秀賞。個人では5月にSOQL構築ツール「LWC SOQL Builder」をリリース(ぜひ使ってください)。