Skip to main content
Trailblazer Community 现已在 Slack 开启公开测试版。欢迎加入并实时交流。加入 Slack

测试 Apex 触发器

学习目标

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

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

备注

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

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

先决条件

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

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

  1. 在 Web Console(Web 控制台)中,按 Ctrl+Shift+P (Windows) 或 ⌘+Shift+P (macOS) 打开命令面板。
  2. 输入 SFDX: Create Apex Trigger(SFDX:创建 Apex 触发器),然后按 Enter 键。
  3. 对于触发器名称,请输入 AccountDeletion,然后按 Enter 键。
  4. 对于 sObject,请选择 Account(客户),然后按 Enter 键。
  5. 对于触发事件,请选择 before delete(删除前),然后按 Enter 键。
  6. 对于输出目录,请选择 force-app/main/default/triggers,然后按 Enter 键。
  7. 将默认触发主体替换为以下示例。
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 WITH USER_MODE]) {
    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. 单击保存。

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

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

重复前面的步骤,禁用 HelloWorldTrigger 和 CalloutTrigger 触发器。

添加并运行单元测试

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

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

  1. 在 Web Console(Web 控制台)中,按 Ctrl+Shift+P (Windows) 或 ⌘+Shift+P (macOS) 打开命令面板。
  2. 输入 SFDX: Create Apex Class(SFDX:创建 Apex 类),然后按 Enter 键。
  3. 对于模板类型,请选择 DefaultApexClass,然后按 Enter 键。
  4. 对于类名称,请选择 TestAccountDeletion,然后按 Enter 键。
  5. 对于输出目录,请选择 force-app/main/default/classes,然后按 Enter 键。
  6. 将默认类主体替换为以下内容。
@IsTest
private with sharing 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 as user acct;
    Opportunity opp = new Opportunity(
      Name=acct.Name + ' Opportunity',
      StageName='Prospecting',
      CloseDate=System.today().addMonths(1),
      AccountId=acct.Id);
    insert as user opp;
    // Perform test
    Test.startTest();
      Database.DeleteResult result = Database.delete(acct, false, AccessLevel.USER_MODE);
    Test.stopTest();
    // Verify
    // In this case the deletion should have been stopped by the trigger,
    // so verify that we got back an error.
    Assert.isFalse(result.isSuccess());
    Assert.isTrue(result.getErrors().size() > 0);
    Assert.areEqual('Cannot delete account with related opportunities.',
      result.getErrors()[0].getMessage());
  }
}

测试方法第一步是创建一个拥有业务机会的测试客户。然后,删除测试客户,该删除操作会触发 AccountDeletion 触发器。测试方法通过检查 Database.delete() 调用的返回值来验证触发器是否阻止删除测试客户。返回值是一个 Database.DeleteResult 对象,其中包含有关删除操作的信息。测试方法验证删除不成功并验证获取的错误提示。

  1. 保存测试类。
  2. 在 Web Console(Web 控制台)中,点击 Activity Bar(活动栏)中的 Testing(测试)图标。Testing(测试)侧面板随即打开。
  3. 在 Testing(测试)搜索栏中,输入 TestAccountDeletion。
  4. 要运行类中的所有测试方法,将鼠标悬停在 TestAccountDeletion 行上,然后点击 Run Test(运行测试)图标。

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

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

了解详细信息

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

Note

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 帮助网站访问新的反馈表单。

了解更多 继续分享反馈