ベストプラクティス
■汎用的なテストデータは@isTest内で準備する
@testSetupで準備したデータは全てのテストメソッドで使いまわすことができます。
そのため、各テストメソッドで共有して使いまわしたいテストデータは、各テストメソッド内ではなく、@testSetupアノテーション付きのメソッド内で事前に準備しておきましょう。
■テストデータの作成は、TestDataFactoryを利用する
TestDataFactoryを利用することで、オブジェクトのメタデータに依存する記述を一箇所に集約できるようになります。
これにより、必須項目の追加や入力規則の追加などがあった場合も、個々のApexを修正しなくともTestDataFactoryだけを変更すればようになり、メンテナンスコストが大幅に削減されます。
■(各メソッドに固有の)テストデータの準備はTest.startTest()よりも前に終わらせておく
Test.startTest()とTest.stopTest()の中は、その外とは別のガバナ制限のコンテクストにおいて動作します。
実際の環境ではデータが事前準備されている(=テストデータ挿入のDML操作がテストに影響を及ぼしてはいけない)ことを考慮すると、Test.startTest()よりも前の段階でテストデータ作成が終了していることが望ましいです。
■System.runAs()を利用する
System.runAs()を利用することで、特定のプロファイルやユーザとしてテストメソッドを実行することが可能です。
常にシステムコンテクストで動作するロジックでない限り、System.runAs()を利用してアクセス権までチェックしましょう。
■AssertをTest.stopTest()よりも後に記述する
非同期処理はTest.stopTest()の次の行よりも前に必ず終了します。
言い換えると、Test.stopTest()には非同期処理を同期処理化する意味合いがあります。
処理結果を検証するはずのAssertが、処理の途中で動作しては全く意味がありませんので、Assertは必ずTest.stopTest()よりも後に記述するようにしましょう。
■クラスとメソッドはそれぞれ下記の規則に従って命名する。
クラス名:テスト対象クラス+Test
- Bad:Test_AccountTrigger
- Good:AccountTrigger_Test
メソッド名:テスト対象メソッド名_シナリオ_期待される動作
- Bad:TestMethod1
- Good:createAccount_DuplicateAccountId_ReturnsDuplicateError
命名規則に関する参考リンク↓
=======TestClassのテンプレート↓=======
TestClass
/*******************************************************************************************
* @CopyRight Eherenfest. Inc.
* @CreatedDate 2021/09/01
* @Description テストクラスforAccountTrigger&AccountTriggerHandler
* @Author りがるでぃ
* @Modification Log
*******************************************************************************************/
@isTest
private class AccountTriggerTest{
@testSetup
static void setup() {
//テストデータ準備(※各メソッドに共通のデータを準備)
Account testAccount = TestDataFactory.createAccount(true);
List<Opportunity> oppList = TestDataFactory.createOpportunity(acc.id,5);
insert oppList;
}
@isTest
static void testMethod() {
//テストデータ準備(※このメソッドに特有のデータを準備)
Account accToUpdate = [SELECT Id,Name FROM Account LIMIT 1];
accToUpdate.name = 'にゃん';
update accToUpdate;
Test.startTest();
System.runAs(new User(ID = UserInfo.getUserID())) {
//テストメソッド実行
}
Test.stopTest();
//結果検証
List<Opportunity> oppListToCheck = [SELECT Id FROM Opportunity];
System.assertEquals(oppListToCheck.size(),5)
}
}
TestDataFactory
/*******************************************************************************************
* @CopyRight Eherenfest. Inc.
* @CreatedDate 2021/09/01
* @Description TestDataFactory
* @Author りがるでぃ
* @Modification Log
*******************************************************************************************/
@isTest
public with sharing class TestDataFactory{
//リード
public static Lead createLead(Boolean doInsert){
Lead newLead = new Lead() ;
newLead.FirstName = 'Taro';
newLead.LastName = 'Yamada';
newLead.Company = 'TestCompany';
if(doInsert){
insert newLead;
}
return newLead;
}
//取引先
public static Account createAccount(Boolean doInsert){
Account acc = new Account();
acc.Name = 'TestAccount';
if(doInsert){
insert acc;
}
return acc;
}
//商談(複数)
public static List<Opportunity>createOpportunity(Id accountId, Integer numOpps) {
List<Opportunity> opps = new List<Opportunity>();
for(Integer i = 1; i <= numOpps; i++) {
Opportunity opp = new Opportunity();
opp.name = 'Account ' + i;
opp.accountId = accountid;
opp.amount = 500;
opp.closeDate = Date.today().addDays(10);
opp.stageName = 'Prospecting';
opps.add(opp);
}
return opps;
}
}
}
TestDataFactory関連のリンク↓
https://github.com/benahm/TestDataFactory
https://github.com/amiller-smg3/Salesforce-Test-Data-Factory