API リファレンス: SPersona
•Apex Stem ドキュメント
Apex StemApexBlueprintSPersonarunAsAPI Reference
System.runAs で使う制限ユーザー (ペルソナ) を生成するビルダー。Profile / PermissionSet の割り当て、安全な既定値、owner() / sharedWith() と組んで敵対的データを宣言する使い方まで。
API リファレンス: SPersona
SPersona は、System.runAs で使う制限ユーザー (ペルソナ) を生成するためのビルダーです。SBlueprint と同じくイミュータブルで、各メソッドが新しいインスタンスを返します。
権限まわりのテストを書こうとすると、テストユーザーの作成に細かい落とし穴が並びます (一意な Username、mixed DML、ロケール既定値、Profile 名の解決)。SPersona はその「正しい 1 つの実装」を 1 クラスに集約しています。UserFactory を自前で書かないでください。
Static ファクトリ
| メソッド | 用途 |
|---|---|
SPersona.of(String name) | 起点。短いペルソナ名 ('sales-rep' など) を渡す。LastName などに使われる |
組み立て
| メソッド | 用途 |
|---|---|
profile(String profileName) | Profile を名前で指定 ('標準ユーザー' / 'Standard User' など)。create() 時に解決され、テスト実行全体でキャッシュされる |
permissionSets(String permissionSetName) | 割り当てる PermissionSet を API 名で 1 つ追加 (ラベルではない) |
permissionSets(List<String> permissionSetNames) | 同上、複数まとめて |
set(String fieldName, Object value) | 任意の User 項目を上書き。SBlueprint.set() と同じく last wins |
生成
| メソッド | 戻り値 | 用途 |
|---|---|---|
create() | User | Profile を解決し、安全な既定値で User を組み立て、PermissionSetAssignment ごと insert して返す |
APEX
User rep = SPersona.of('sales-rep')
.profile('標準ユーザー')
.permissionSets('InvoiceReadOnly')
.set('LanguageLocaleKey', 'ja')
.create();
知っておくべき挙動
- Username は UUID で払い出されるので、テストの並列実行でも衝突しません
- ロケール系の既定値は実行ユーザー基準で埋まります (org に依存しない)。変えたければ
set()で上書き - mixed DML を内部で回避しています (
System.runAsでラップして insert)。通常の DML と混ぜて呼んで構いません create()はテストコンテキスト専用です。System.runAsに依存するため、本番コードからは呼べません- キャッシュはしません。呼ぶたびに新しいユーザーが作られます (Profile 名 → Id の解決だけがキャッシュされます)
- ⚠️ Profile 名はロケール依存です。日本語 org では
'標準ユーザー'、英語 org では'Standard User'になります
敵対的データとセットで使う
SPersona が本領を発揮するのは、SBlueprint の owner() / sharedWith() と組み合わせたときです。「管理者が所有し、テスト対象のペルソナには最小限だけ共有する」という敵対的なデータを宣言できます。
APEX
User admin = SPersona.of('admin').profile('システム管理者').create();
User rep = SPersona.of('sales-rep').profile('標準ユーザー').create();
SOrchestrator orchestrator = SOrchestrator.start()
.add(
SBlueprint.of(Invoice__c.class).alias('inv')
.owner(admin) // admin 所有
.sharedWith(rep, 'Read')); // rep には Read だけ
orchestrator.create();
System.runAs(rep) {
// rep から何が見えるか / 何が書けるかを検証する
}
sharedWith の有無が、そのまま可視性の期待値になります。共有を宣言していないレコードが runAs の中で見えてしまったら、それは共有設定の穴です。
プロジェクト側での集約
Blueprints.cls と同じ考え方で、プロジェクト固有のペルソナは単一の Personas.cls に集約します。テストごとに Profile 名や PermissionSet 名を直書きすると、org 側の改名で一斉に壊れたときの修正箇所が散らばります。
APEX
public with sharing class Personas {
/** 一般の営業担当 */
public static User salesRep() {
return SPersona.of('sales-rep')
.profile('標準ユーザー')
.permissionSets('InvoiceReadOnly')
.create();
}
}
関連ドキュメント
- API リファレンス: SBlueprint:
owner/sharedWithで敵対的データを宣言する - API リファレンス: SOrchestrator: 依存解決と実 DML
- ApexBlueprint ガイド: ガイド目次に戻る