function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
kosukekosuke 

トリガで親オブジェクトの値を更新したい

お世話になります。
初歩的な質問で申し訳ないのですが、

 子オブジェクトにデータが挿入されたら、参照関係の親オブジェクトの項目の値を
更新するというトリガを作りたいのですが、
テストクラスを作成してもうまく動作してくれません。
原因が中々掴めずにいます。。。ご教授いただければと思います。


 開発環境
 Eclipse  4.2.2
api version 29.0
です。

コードは以下のとおりです。
apexトリガ
trigger SyousaiCreate on AAAA__c (after insert) {
  List<AAAA__c> values = Trigger.new;
  AAAA__c  value = values[0];
  List<BBBB__c> InsertDatas = [SELECT Id, total_money__c  from BBBB__c where Id = :value.BBBB_Relation__c];
  BBBB__c InsertData = null;
  if(InsertDatas.size() > 0){
    InsertData = InsertDatas[0];
    InsertData.total_money__c = InsertData.total_money__c + value.money__c;
    Update(InsertDatas);
  }
}
テストクラス
@isTest
private class testinsertSyosai {
  static testmethod void testclass(){
    AAAA__c InsertData_Syosai = new AAAA__c(BBBB_Relation__c = 'a001000000XXXXX' ,money__c = 5000);
    insert(InsertData_Syosai);
  }
}

※ BBBB_Relation__c が参照項目となっており、データは存在することを確認しています。

Best Answer chosen by kosuke
Taiki YoshikawaTaiki Yoshikawa
子オブジェクトが登録 (INSERT) されたときに親オブジェクトが更新されるトリガーということなので、
取引先と取引先責任者を例に説明させて頂きます。

最初にApexトリガーの処理はトリガーに直接書くのではなくHandlerクラスなどに書くようにすると管理しやすくなります。

Apexトリガー
trigger ContactTrigger on Contact (after insert) {
    
    ContactTriggerHandler handler = new ContactTriggerHandler();
    
    if (Trigger.isAfter) {
        if (Trigger.isInsert) {
            // 取引先責任者作成時に取引先を更新
            handler.updateAccount(Trigger.new);
        }
    }
}

Handlerクラス
public with sharing class ContactTriggerHandler {

    public ContactTriggerHandler() {
        
    }

    public void updateAccount(List<Contact> prmContacts) {
        
        // 最初に取引先責任者に紐付く取引先IDを取得
    	Set<Id> accountIds = new Set<Id>();
        for (Contact c : prmContacts) {
            if (String.isNotEmpty(c.AccountId)) {
            	accountIds.add(c.AccountId);
            }
        }

        // 取引先IDを条件に取引先を取得する
        List<Account> accounts = [SELECT Id,Name FROM Account
                                                                WHERE Id IN: accountIds];

        // 取引先に値をセットする
        for (Account a : accounts) {
        	a.Name = a.Name + '★';
        }

        // 取引先を更新する
        update accounts;
    }
}

大雑把ですがだいたいこんな感じです。
これで子オブジェクト(取引先責任者)が登録されたときに親オブジェクト(取引先)の値を変更して更新するという動きになります。


本題のテストクラスの方ですが、まずテストクラスでは組織に作られた既存のデータにはアクセスできないようになっています。
今回テストクラスが正常に実行できていないのは、親オブジェクトのデータをテストクラス内で用意していないことが原因と思われます。

テストデータの作成も含めてテストクラスの書き方はこんな感じになります。

テストクラス
@isTest
private class ContactTriggerHandlerTest {

    static testMethod void updateAccountTest() {
        
        // 取引先のテストデータ作成
        Account account = new Account(
            Name = 'TEST'
        );
        insert account;
        
        // 取引先のINSERT結果確認
        System.assertEquals(String.isNotEmpty(account.Id), true);

        // 登録する取引先責任者の準備
        Contact contact = new Contact(
        	 LastName = 'TestName'
        	,AccountId = account.Id
        );

        Test.startTest();

        // 取引先責任者をINSERT (トリガーが実行される)
        insert contact;

        // トリガーの処理結果を確認する
        // 最新の取引先情報を取得
        Account accountResult = [SELECT Id,Name FROM Account WHERE Id =: account.Id LIMIT 1];

        // Name項目に★が追加されていることを確認
        System.assertEquals(accountResult.Name, account.Name + '★');

        Test.stopTest();
    }
}
これも大雑把な書き方をしていますが、テストクラスの処理はだいたいこんな流れになります。