Skip to main content

测试 Apex 触发器

学习目标

完成本单元后,您将能够:

  • 为单个记录操作触发的触发器编写测试。
  • 在同一个类中执行所有测试方法。
备注

备注

用中文(简体)学习?在中文(简体)Trailhead Playground 中开始挑战,用括号中提供的译文完成挑战。仅复制并粘贴英文值,因为挑战验证基于英文数据。如果在中文(简体)组织中没有成功通过挑战,我们建议您 (1) 将区域设置切换为美国,(2) 按此处说明将语言切换为英文,(3) 再次单击“检查挑战”按钮。

查看 Trailhead 本地化语言徽章详细了解如何利用 Trailhead 译文。

测试 Apex 触发器

在部署触发器之前,编写单元测试以执行触发触发器并验证预期结果的操作。

让我们来测试一个在 Apex 触发器模块中使用过的触发器。如果某个客户记录具有关联的业务机会,则 AccountDeletion 触发器会阻止删除该记录。

先决条件

如果您还未添加 AccountDeletion 触发器,请执行如下步骤。

  1. 在 Developer Console 中,单击 File(文件) | New(新建) | Apex Trigger(Apex 触发器)
  2. 输入 AccountDeletion 作为触发器名称,然后为 sObject 选择 Account(客户)。单击提交
  3. 将默认代码替换为以下内容。
    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 触发器,但已禁用了该触发器以便系统检测您的挑战,请重新启用该触发器。

  1. 在 Setup(设置)中,搜索 Apex Triggers(Apex 触发器)。
  2. 在 Apex Triggers(Apex 触发器)页面中,单击 AccountDeletion 触发器旁边的 Edit(编辑)
  3. 选择 Is Active(有效)
  4. 单击保存

如果组织中包含上一个单元创建的 AddRelatedRecordCalloutTriggerHelloWorldTrigger 触发器,请禁用这些触发器。例如,要禁用 AddRelatedRecord 触发器,请执行以下操作:

  1. 在 Setup(设置)中,搜索 Apex Triggers(Apex 触发器)。
  2. 在 Apex Triggers(Apex 触发器)页面中,单击 AddRelatedRecord 触发器旁边的 Edit(编辑)
  3. 取消选择 Is Active(有效)
  4. 单击保存

重复前面的步骤,禁用 HelloWorldTriggerCalloutTrigger 触发器。

添加并运行单元测试

首先,让我们从添加一个测试方法开始。此测试方法验证触发器的设计目标(正向用例):防止客户在拥有关联业务机会时被删除。

  1. 在 Developer Console 中,单击 File(文件)| New(新建)| Apex Class(Apex 类)
  2. 输入 TestAccountDeletion 作为类名称,然后单击 OK(确定)
  3. 将默认类主体替换为以下内容。
    @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 对象,其中包含有关删除操作的信息。测试方法验证删除不成功并验证获取的错误提示。
  4. 要运行该测试,请依次单击 Test(测试)| New Run(新运行)
  5. 在 Test Classes(测试类)下方,单击 TestAccountDeletion
  6. 要将 TestAccountDeletion 类中的所有测试方法添加到测试运行中,请单击 Add Selected(添加所选项)
  7. 单击运行。在最新运行的 Tests(测试)选项卡中查找测试结果。

TestAccountDeletion 测试类只包含一个测试方法,用于测试单个客户记录。这同样也是正向用例的测试。测试更多场景以确保触发器适用于所有情况,包括删除没有业务机会的客户和批量删除客户。

测试数据是在测试方法内部设置的,当您添加更多测试方法时,这可能会很耗时。如果您有多种测试方法,请将创建的测试数据放在一个测试实用程序类中,并从多种测试方法中调用该实用程序类。下一个单元将向您展示如何利用测试实用程序类并添加更多的测试方法。

了解详细信息

测试方法包含 Test.startTest()Test.stopTest() 方法对,用于界定获取一组新调控器限制的代码块。在该测试中,执行测试之前建立测试数据使用了两个 DML 语句。要测试 Apex 代码是否在调控器限制内运行,请将数据建立与测试的限制使用情况分离。要分离数据建立进程的限制使用情况,请将测试调用包含在 Test.startTest()Test.stopTest() 块中。测试异步 Apex 时也使用该测试块。有关更多信息,请参见使用限制、startTest 以及 stopTest

备注

Developer Console 的一个已知问题阻止它在运行测试子集时正确更新代码覆盖率。要更新代码覆盖率结果,请使用 Test(测试) | Run All(运行所有),而不是 Test(测试) | New Run(新运行)

资源

准备好迎接实践挑战

为了完成本单元的实践挑战,您需要使用下面的代码在联系人对象上创建一个名为 RestrictContactByName 的 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');

    }

  }

}
在 Salesforce 帮助中分享 Trailhead 反馈

我们很想听听您使用 Trailhead 的经验——您现在可以随时从 Salesforce 帮助网站访问新的反馈表单。

了解更多 继续分享反馈