Apex トリガーをテストする
学習の目的
この単元を完了すると、次のことができるようになります。
- 単一レコード操作を起動するトリガーのテストを記述する。
- クラスのすべてのテストメソッドを実行する。
Apex トリガーをテストする
トリガーをリリースする前に、トリガーを起動するアクションを実行し、結果が予想どおりであることを確認する単体テストを記述します。
「Apex トリガー」モジュールで取り上げたトリガーをテストしましょう。取引先レコードに商談が関連付けられている場合、AccountDeletion
トリガーはレコードが削除されるのを防ぎます。
前提条件
まだ AccountDeletion
トリガーを追加していない場合は、次の手順に従います。
- 開発者コンソールで、[File (ファイル)] | [New (新規)] | [Apex Trigger (Apex トリガー)] をクリックします。
- トリガー名に「
AccountDeletion
」と入力して、sObject に [Account (取引先)] を選択します。[送信] をクリックします。 - デフォルトのコードを次のコードに置き換えます。
trigger AccountDeletion on Account (before delete) { // Prevent the deletion of accounts if they have related opportunities. for(Account a : [SELECT Id FROM Account WHERE Id IN (SELECT AccountId FROM Opportunity) AND Id IN :Trigger.old]) { Trigger.oldMap.get(a.Id).addError('Cannot delete account with related opportunities.'); } }
前の単元で AccountDeletion
トリガーを追加し、システムで問題をチェックできるように無効化してある場合は、再び有効にします。
- [Setup (設定)] から
「Apex Triggers 」
(Apex トリガー) を検索します。 - [Apex Triggers (Apex トリガー)] ページで、
AccountDeletion
トリガーの横にある [Edit (編集)] をクリックします。 - [Is Active (有効)] を選択します。
- [保存] をクリックします。
前の単元で取り上げた AddRelatedRecord
、CalloutTrigger
、または HelloWorldTrigger
というトリガーが組織にある場合は、無効にします。たとえば、AddRelatedRecord
トリガーを無効にする手順は、次のとおりです。
- [Setup (設定)] から
「Apex Triggers 」
(Apex トリガー) を検索します。 - [Apex Triggers (Apex トリガー)] ページで、
AddRelatedRecord
トリガーの横にある [Edit (編集)] をクリックします。 - [Is Active (有効)] をオフにします。
- [保存] をクリックします。
HelloWorldTrigger
トリガーと CalloutTrigger
トリガーを無効にするには、上記の手順を繰り返します。
単体テストを追加し、実行する
最初に、テストメソッドを追加してみましょう。このテストメソッドでは、トリガーが設計された目的 (ポジティブケース) を検証します。つまり、取引先に商談が関連付けられている場合はその取引先が削除されないようにします。
- 開発者コンソールで、[File (ファイル)] | [New (新規)] | [Apex Class (Apex クラス)] をクリックします。
- クラス名として「
TestAccountDeletion
」と入力し、[OK] をクリックします。 - デフォルトのクラス本文を次のコードで置き換えます。このテストメソッドでは最初に、商談のあるテスト取引先を設定します。次に、このテスト取引先を削除すると、この操作によって
@isTest private class TestAccountDeletion { @isTest static void TestDeleteAccountWithOneOpportunity() { // Test data setup // Create an account with an opportunity, and then try to delete it Account acct = new Account(Name='Test Account'); insert acct; Opportunity opp = new Opportunity( Name=acct.Name + ' Opportunity', StageName='Prospecting', CloseDate=System.today().addMonths(1), AccountId=acct.Id); insert opp; // Perform test Test.startTest(); Database.DeleteResult result = Database.delete(acct, false); Test.stopTest(); // Verify // In this case the deletion should have been stopped by the trigger, // so verify that we got back an error. System.assert(!result.isSuccess()); System.assert(result.getErrors().size() > 0); System.assertEquals('Cannot delete account with related opportunities.', result.getErrors()[0].getMessage()); } }
AccountDeletion
トリガーが実行されます。テストメソッドで、Database.delete()
コールの戻り値をチェックして、トリガーによってテスト取引先の削除が防止されたことを確認します。戻り値のDatabase.DeleteResult
オブジェクトには、削除操作に関する情報が含まれます。テストメソッドで、削除が行われなかったことと、エラーメッセージが取得されたことを確認します。 - このテストを実行するには、[Test (テスト)] | [New Run (新規実行)] をクリックします。
- [Test Classes (テストクラス)] の下で、[TestAccountDeletion] をクリックします。
TestAccountDeletion
クラスのすべてのメソッドをテスト実行に追加するには、[Add Selected (選択項目を追加)] をクリックします。- [実行] をクリックします。[Tests (テスト)] タブの最新の実行で、テスト結果を見つけます。
TestAccountDeletion
テストクラスには、1 つの取引先レコードをテストする 1 つのテストメソッドのみが含まれます。また、このテストはポジティブケースが対象です。商談のない取引先の削除や取引先の一括削除など、必ず他のシナリオもテストして、すべてのケースでトリガーが機能することを確認します。
テストデータはテストメソッド内部に設定されるため、さらにテストメソッドを追加していくと、設定に時間がかかる場合があります。多くのテストメソッドがある場合は、テストデータの作成をテストユーティリティクラスに入れて、複数のテストメソッドからそのユーティリティクラスをコールします。次の単元では、テストユーティリティクラスを利用して、さらにいくつかのテストメソッドを追加する方法ついて説明します。
もうひとこと...
テストメソッドには、Test.startTest()
メソッドと Test.stopTest()
メソッドのペアが含まれます。このペアによって、ガバナ制限の最新セットを取得するコードのブロックが区切られます。このテストでは、テストを実行する前に、テストデータの設定に 2 つの DML ステートメントが使用されます。その Apex コードがガバナ制限内で実行されることをテストするには、データ設定の使用制限をテストの使用制限と切り離す必要があります。データ設定プロセスの使用制限を切り離すには、テストコールを Test.startTest()
と Test.stopTest()
のブロックで囲みます。このテストブロックは、非同期 Apex をテストする場合にも使用します。詳細は、「Limits、startTest、および stopTest の使用」を参照してください。
リソース
ハンズオン Challenge の準備をする
この単元のハンズオン Challenge を完了するには、以下のコードを使用して RestrictContactByName
という名前の Contact オブジェクトに Apex トリガーを作成する必要があります。
trigger RestrictContactByName on Contact (before insert, before update) { //check contacts prior to insert or update for invalid data for(Contact c : Trigger.New) { if(c.LastName == 'INVALIDNAME') { //invalidname is invalid c.AddError('The Last Name "'+c.LastName+'" is not allowed for DML'); } } }