【问题标题】:Access Trigger.New value in Apex Test Class访问 Trigger.Apex 测试类中的新值
【发布时间】:2019-07-22 23:23:34
【问题描述】:

tl;dr - 如何让测试类等到特定触发器完成更新或插入后再继续测试?

背景

我有一个触发器,它会在创建 Account 对象时创建一个新的 Portal_Content__c 对象,然后将两个记录相互关联(请参阅下面的Account Trigger)。

我还在Portal_Content__c 对象上创建了一个触发器,该触发器在删除记录时触发。删除后,触发器会查找相关的 Account 记录并将其删除(请参阅下面的门户内容触发器)。

我的问题是关于我的门户内容测试类(下面的最终代码块)。当我对帐户记录运行 DML 插入时,帐户触发器 应该使用帐户触发器中创建的门户内容记录填充 a.Portal_Content_Record__c 字段。但是,当我运行 system.debug() 测试时,它显示运行 SOQL 查询时 a.Portal_Content_Record__c 字段为空。我已经能够通过匹配名称搜索门户内容记录来绕过此问题,但我想通过按确切 ID 搜索来使脚本更加健壮。

问题

如何让 Portal Content Test Class 等到 Account Trigger 填充 a.Portal_Content_Record__c 字段后再继续测试?

--代码块--

帐户触发器

trigger AccountHandler on Account (before insert, after insert, after update, after delete) {

    List<Account> alist = Trigger.New;
    List<Account> oldlist = Trigger.Old;

//  Create new Portal Content with same name as Account if Account is record type 'College/University,'
//  then assign newly created Portal Content to 'Portal Content Record' lookup field on new Account
    if(Trigger.isBefore && Trigger.isInsert){

        for(Account a : alist) {

            if (a.RecordTypeId == '012i0000001Iy1H') {
                Portal_Content__c p = new Portal_Content__c(
                    Name=a.Name,
                    RecordTypeId='012i0000001J1zZ'
                );
                insert p;

                a.Portal_Content_Record__c = p.Id;
            }
        }
    }

//  Delete Portal Content record referenced in an Account's 'Portal Content Record' lookup field
//  if the Account is deleted

    if (Trigger.isAfter && Trigger.isDelete){
        for(Account a : oldlist){
            for(Portal_Content__c p : [SELECT ID FROM Portal_Content__c WHERE ID = :a.Portal_Content_Record__c]){
                delete p;
            }
        }

    }

//  After the new Portal Content record has been created, assign the Account ID of the Account that created it
//  to the 'School SFDC ID' field on the new Portal Content record.    
    if (Trigger.isAfter && Trigger.isInsert){
        for(Account a : alist){

            List<Portal_Content__c> plist = [SELECT ID FROM Portal_Content__c WHERE Id = :a.Portal_Content_Record__c];

            for(Portal_Content__c p : plist){
                p.School_SFDC_ID__c = a.Id;
                update p;
            }

        }
    }

//  Prevent more than one Account from being assigned to a single Portal Content record
    if (Trigger.isAfter && Trigger.isUpdate) {
        for(Account a : alist){
            if (a.Portal_Content_Record__c != null){
                List<Account> alist = [SELECT ID FROM Account WHERE Portal_Content_Record__c = :a.Portal_Content_Record__c];
                system.debug('alist: ' + alist);
                if (alist.size() > 1) {
                    a.addError('The Portal Content record you selected is already associated with another School. Please select a different Portal Content record');
                }
            }
        }
    }
}

门户内容触发器

trigger PortalContentHandler on Portal_Content__c (before insert, after update, after insert, after delete) {

//  If Portal Content is deleted and Account is tied to Account record, delete Account record
    if(Trigger.isAfter && Trigger.isDelete){
        List<Portal_Content__c> plist = Trigger.old;
        for(Portal_Content__c p : plist) {
            List<Account> alist = [SELECT ID FROM Account WHERE Id = :p.School_SFDC_ID__c];
            for(Account a : alist){
                delete a;
            }       
        }
    }

//  If more than one Portal Content with the same name, prevent new Portal Content record from being created
    else if(Trigger.isAfter && (Trigger.isUpdate || Trigger.isInsert)){
        List<Portal_Content__c> plist = Trigger.New;
        for(Portal_Content__c p : plist){
            List<Portal_Content__c> pquery = [SELECT ID FROM Portal_Content__c WHERE Name = :p.Name];
            if(pquery.size() > 1){
                p.addError('There is already a Portal Content record with this name. Please select a different name.');
            }
        }
    }
}

门户内容测试类

@isTest
public class PortalContentHandlerTest {

    @isTest static void createThenDeletePortalContent(){
        Account a = new Account(Name='deletePortalTest',RecordTypeId='012i0000001Iy1H');
        insert a;

        List<Portal_Content__c> plist = [SELECT ID FROM Portal_Content__c WHERE Name = :a.Name];//Id = :a.Portal_Content_Record__c];

        system.debug('Delete Info: a.Id = ' + a.Id + ', Portal_Content_Record = ' + a.Portal_Content_Record__c+ ', plist = ' + plist);
        for(Portal_Content__c p : plist){
            delete p;            
        }
        system.debug('Delete Info: a.Id = ' + a.Id);
        List<Account> checklist = [SELECT ID FROM Account WHERE Id = :a.Id];
        system.debug(checklist);
        system.assertEquals(0, checklist.size());
    }

【问题讨论】:

    标签: triggers salesforce apex apex-code test-class


    【解决方案1】:

    我已经在我的 Org.请在下面找到我的 cmets。

    • 根据您的要求,我有一个触发器,它会在创建 Account 对象时创建一个新的 Portal_Content__c 对象,然后将两条记录相互关联(请参阅下面的 Account Trigger)。
      我看到Account(Portal_Content_Record__c )Portal Content (School_SFDC_ID__c) 之间存在关系。您正在设置Portal_Content_Record__c。但您还需要链接School_SFDC_ID__c 以满足您的要求。请找到以下代码

      trigger AccountHandler on Account (before insert, after insert, after update, after delete) {
      
              List<Account> alist = Trigger.New;
              List<Account> oldlist = Trigger.Old;
      
          //  Create the new Portal Content with the same name as Account if Account is record type College/University,
          //  then assign newly created Portal Content to Portal Content Record lookup field on new Account
              if(Trigger.isBefore && Trigger.isInsert){
      
                  for(Account a : alist) {
      
                      if (a.RecordTypeId == '012i0000001Iy1H') {
                          Portal_Content__c p = new Portal_Content__c(
                              Name=a.Name,
                              RecordTypeId='012i0000001J1zZ',
                              School_SFDC_ID__c = a.id
                          );
                          insert p;
      
                          a.Portal_Content_Record__c = p.Id;
                      }
                  }
              }
          }
      
    • 我看到唯一的问题是 delete 没有被覆盖 PortalContentHandler 因为不符合条件 List<Account> alist = [SELECT ID FROM Account WHERE Id = :p.School_SFDC_ID__c]; 在创建时填充它 门户内容如上点所述。

    • 此外,您需要更改您的测试类,因为没有您尝试查询的门户内容数据。在测试类中,您只获得您在那里创建的数据。 AccountHandler 创建的那个不会成为您的测试类的一部分。创建与您在触发器中创建的数据相同的数据。

      @isTest 
      public class PortalContentHandlerTest {
      
      @isTest static void createThenDeletePortalContent(){
          Account a = new 
          Account(Name='deletePortalTest',RecordTypeId__c='012i0000001Iy1H');
          insert a;
          Portal_Content__c p = new Portal_Content__c(
              Name=a.Name,
              RecordTypeId__c='012i0000001J1zZ',
              School_SFDC_ID__c = a.id
          );
          insert p;
          delete p; 
      }
      
      }
      

    【讨论】:

    • 嗨@Lavika!我意识到我没有包含所有的 AccountHandler 和 PortalContentHandler 触发器;我现在已经更新它们以包含整个代码块。当我尝试将 p.School_SFDC_ID__c 作为 AccountHandler 中 Trigger.isBefore &amp;&amp; Trigger.isInsert 块的一部分分配时,a.Id 为 null 并将 null 分配给 p。我现在在帖子中使用Trigger.isAfter &amp;&amp; Trigger.isInsert 绕过了这个。关于createThenDeletePortalContent方法,p应该已经被AccountHandler触发器创建了,不需要通过方法手动输入。
    猜你喜欢
    • 2018-09-12
    • 2021-09-24
    • 2022-01-12
    • 2015-02-21
    • 2018-08-13
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多