Apex 测试(3)

学习目标

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

  • 创建一个测试工具类。
  • 使用测试实用程序方法为各种测试用例设置测试数据。
  • 执行一个类中的所有测试方法。

为Apex测试创建测试数据

使用测试实用程序类为测试数据设置添加可重用的方法。

先决条件

如果您还没有这样做,请完成上一个单元“测试Apex触发器”中的先决条件。

添加一个测试工具类

让我们通过用一个实用程序类方法的调用替换测试数据创建来重构以前的测试方法。首先,您需要创建测试实用程序类。

TestDataFactory类是一种特殊的类,它是一个公共类,它是用isTest注释的,只能从正在运行的测试中访问。测试工具类包含可以被测试方法调用来执行有用任务的方法,例如设置测试数据。测试工具类从组织的代码大小限制中排除。

要添加TestDataFactory类:

  1. 在开发者控制台中,点击 File | New | Apex Class, 然后输入TestDataFactory作为类名,然后单击OK。
  2. 用下面的代码替换默认的类体。
    @isTest
    public class TestDataFactory {
        public static List<Account> createAccountsWithOpps(Integer numAccts, Integer numOppsPerAcct) {
            List<Account> accts = new List<Account>();
            
            for(Integer i=0;i<numAccts;i++) {
                Account a = new Account(Name='TestAccount' + i);
                accts.add(a);
            }
            insert accts;
            
            List<Opportunity> opps = new List<Opportunity>();
            for (Integer j=0;j<numAccts;j++) {
                Account acct = accts[j];
                // 对于刚插入的每个客户,添加机会
                for (Integer k=0;k<numOppsPerAcct;k++) {
                    opps.add(new Opportunity(Name=acct.Name + ' Opportunity ' + k,
                                           StageName='Prospecting',
                                           CloseDate=System.today().addMonths(1),
                                           AccountId=acct.Id));
                }
            }
            // 插入所有客户的所有机会
            insert opps;
            
            return accts;
        }
    }
    此测试实用程序类包含一个静态方法createAccountsWithOpps(),该方法接受numAccts参数中保存的客户数量以及为每个客户(保存在numOppsPerAcct参数中)创建的相关机会数量。方法中的第一个循环创建了指定数量的客户并将其存储在accts列表变量中。在第一个循环之后,将调用insert()DML语句在数据库的列表中创建所有客户。

第二个循环创造了机会。由于每个机会组都链接到一个客户,所以外部循环通过客户进行迭代,并包含一个嵌套的循环,为当前客户创建相关的机会。下次运行嵌套循环时,使用add()方法将机会添加到同一个列表中。使用AccountId字段将机会链接到其父客户。创建的所有机会总数是机会数量与客户数量的乘积(numOppsPerAcct * numAccts)。接下来,在循环之外有效地调用insert()DML语句,以便仅在一个调用中为所有客户创建集合中的所有机会。

最后,这个方法返回新客户的列表。

注意

尽管此方法不会返回相关的机会,但您可以通过编写SOQL查询来获取这些记录,该查询利用Account和Opportunity之间的现有关系,例如Testing Apex Triggers中的触发器中使用的查询。

调用测试数据创建的实用程序方法

现在您已经添加了测试实用程序类,请修改测试类以利用此类。在TestAccountDeletion类中,替换以// Test data setup开始的块,并以insert opp结束:

        // 测试数据设置
        // 通过调用实用程序方法创建一个拥有一个机会的客户
        Account[] accts = TestDataFactory.createAccountsWithOpps(1,1);
TestDataFactory.createAccountsWithOpps(1,1)调用返回的数组包含一个Account sObject。

这是修改后的测试方法。更短的版本!

@isTest
private class TestAccountDeletion {

    @isTest static void TestDeleteAccountWithOneOpportunity() {
        // 测试数据设置
        // 通过调用实用程序方法创建一个拥有一个机会的客户
        Account[] accts = TestDataFactory.createAccountsWithOpps(1,1);
        
        // 执行测试
        Test.startTest();
        Database.DeleteResult result = Database.delete(accts[0], false);
        Test.stopTest();

        // 验证删除是否应该被触发器停止,
        // 检查我们是否收到错误
        System.assert(!result.isSuccess());
        System.assert(result.getErrors().size() > 0);
        System.assertEquals('不能删除有相关机会的客户.',
                             result.getErrors()[0].getMessage());
    }        
}

测试不同的条件

一种测试方法不足以测试触发器的所有可能输入。我们需要测试一些其他条件,例如何时删除没有机会的客户。我们还需要使用批量数量的记录来测试相同的方案,而不是只记录一个记录。这里是包含三个附加测试方法的测试类的更新版本。保存此类更新的版本。

@isTest
private class TestAccountDeletion {

    @isTest static void TestDeleteAccountWithOneOpportunity() {
        // 测试数据设置
        // 通过调用实用程序方法创建一个拥有一个机会的客户
        Account[] accts = TestDataFactory.createAccountsWithOpps(1,1);
        
        // Perform test
        Test.startTest();
        Database.DeleteResult result = Database.delete(accts[0], false);
        Test.stopTest();

        // 验证删除是否应该被触发器停止,
        // 检查我们是否收到错误
        System.assert(!result.isSuccess());
        System.assert(result.getErrors().size() > 0);
        System.assertEquals('不能删除有相关机会的客户',
                             result.getErrors()[0].getMessage());
    }
    
    @isTest static void TestDeleteAccountWithNoOpportunities() {
        // 测试数据设置
        // 通过调用实用程序方法创建一个没有机会的客户
        Account[] accts = TestDataFactory.createAccountsWithOpps(1,0);
        
        // 执行测试
        Test.startTest();
        Database.DeleteResult result = Database.delete(accts[0], false);
        Test.stopTest();

        //验证删除是否成功
        System.assert(result.isSuccess());
    }
    
    @isTest static void TestDeleteBulkAccountsWithOneOpportunity() {
        // 测试数据设置
        // 通过调用一个实用程序方法创建每个客户
        Account[] accts = TestDataFactory.createAccountsWithOpps(200,1);
        
        // 执行测试
        Test.startTest();
        Database.DeleteResult[] results = Database.delete(accts, false);
        Test.stopTest();

        // 验证每个记录。
        // 在这种情况下,删除应该已经被触发器停止,
        // 检查我们是否收到错误
        for(Database.DeleteResult dr : results) {
            System.assert(!dr.isSuccess());
            System.assert(dr.getErrors().size() > 0);
            System.assertEquals('不能删除有相关机会的客户',
                                 dr.getErrors()[0].getMessage());
        }
    }
    
    @isTest static void TestDeleteBulkAccountsWithNoOpportunities() {
        // 测试数据设置
        // 通过调用实用程序方法创建没有机会的客户
        Account[] accts = TestDataFactory.createAccountsWithOpps(200,0);
        
        // 执行测试
        Test.startTest();
        Database.DeleteResult[] results = Database.delete(accts, false);
        Test.stopTest();

        // 对于每条记录,验证删除是否成功
        for(Database.DeleteResult dr : results) {
            System.assert(dr.isSuccess());
        }
    }
}
运行所有测试方法

最后一步是在我们的测试类中运行测试方法,现在该类包含更全面的测试,并被重构为使用测试数据工厂。由于您已经在TestAccountDeletion类中运行了测试,因此您可以重新运行此测试类以运行其所有测试方法。

  1. 要执行相同的测试运行,请单击测试选项卡,选择您的测试运行,然后单击Test | Rerun.
  2. 通过展开最新的测试运行来检查“测试”选项卡中的结果。测试运行应报告所有四个测试通过!

Apex 测试(2)

学习目标

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

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

测试Apex 触发器

在部署触发器之前,编写单元测试以执行触发触发器的操作并验证预期的结果。
让我们测试一下我们之前在Writing Apex Triggers单元中使用的触发器。如果一个客户记录有相关的机会,AccountDeletion触发器将阻止记录的删除。

先决条件

  1. 如果您尚未添加AccountDeletion触发器,请按照下列步骤操作。
    1. 在开发者控制台中,点击File | New | Apex Trigger.
    2. 输入AccountDeletion作为触发器名称,然后选择sObject的Account。点击Submit.
    3. 用下面的代码替换默认的代码。
      trigger AccountDeletion on Account (before delete) {
         
          // 如果他们有相关的联系人,防止删除客户。
          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(
                  '不能删除有相关机会的帐号');
          }
          
      }
  2. 如果您在之前的单元中添加了AccountDeletion触发器,但已将其禁用,以便系统可以检查您的挑战,请重新启用它。
    1. 从设置中搜索 Apex Triggers.
    2. 在Apex触发器页面上,单击AccountDeletion触发器旁边的Edit
    3. 选择Is Active.
    4. 点击Save.
  3. 如果您的组织包含以前的单元(称为AddRelatedRecord,CalloutTrigger或HelloWorldTrigger)的触发器,请禁用它们。例如,要禁用AddRelatedRecord触发器:
    1. 从设置中搜索 Apex Triggers.
    2. 在Apex触发器页面上,单击AddRelatedRecord触发器旁边的 Edit .
    3. 取消选择Is Active.
    4. 点击Save.
  4. 要禁用HelloWorldTrigger和CalloutTrigger触发器,请重复上述步骤。

添加和运行单元测试

首先,我们开始添加一个测试方法。这个测试方法验证触发器设计要做什么(正面情况):防止一个客户被删除,如果它有相关的机会。

  1. 在开发者控制台中,点击 File | New | Apex Class.
  2. 输入TestAccountDeletion作为类名称,然后单击 OK.
  3. 用下面的代码替换默认的类体。
    @isTest
    private class TestAccountDeletion {
    
        @isTest static void TestDeleteAccountWithOneOpportunity() {
            // 测试数据设置
            // 创建一个有机会的客户,然后尝试删除它
            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;
            
            // 执行测试
            Test.startTest();
            Database.DeleteResult result = Database.delete(acct, false);
            Test.stopTest();
    
            // 验证
            // 在这种情况下,删除应该已经被触发器停止,
            // 确认我们收到了错误
            System.assert(!result.isSuccess());
            System.assert(result.getErrors().size() > 0);
            System.assertEquals('不能删除有相关机会的客户',
                                 result.getErrors()[0].getMessage());
        }
        
    }

    测试方法首先建立一个机会的测试客户。接下来,它将删除测试客户,该客户触发AccountDeletion触发器。测试方法通过检查Database.delete()调用的返回值来验证触发器是否阻止删除测试客户。返回值是一个Database.DeleteResult对象,其中包含有关删除操作的信息。测试方法验证删除不成功并验证获得的错误消息。

  4. 要运行此测试,请单击 Test | New Run.
  5. 在Test Classes下,单击TestAccountDeletion。
  6. 要将TemperatureConverterTest类中的所有方法添加到测试运行中,请单击添加 Add Selected.
  7. 点击Run.

    在最新运行的“测试”选项卡中找到测试结果。

TestAccountDeletion测试类只包含一个测试方法,用于测试单个客户记录。此外,这个测试是针对正面的情况。始终测试更多方案,以确保触发器在所有情况下都能正常工作,包括删除没有机会的客户和批量客户删除。

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

告诉我更多

测试方法包含Test.startTest()和Test.stopTest()方法对,该方法对代码块进行分隔,得到一组新的控制器限制。 在此测试中,测试数据设置在执行测试之前使用两个DML语句。 要测试Apex代码在限速范围内运行,请将数据设置的限制使用与测试隔离。 要隔离数据设置过程的限制使用,请将测试调用包含在Test.startTest()和Test.stopTest()块中。 测试异步Apex时也使用此测试块。 有关更多信息,请参阅使用限制,startTest和stopTest。

注意

开发人员控制台的一个已知问题是,在运行测试子集时,无法正确更新代码覆盖率。 要更新代码覆盖率结果,请使用 Test | Run All 而不是Test | New Run.

Apex 测试(1)

学习目标

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

  • 描述Apex单元测试的主要优点。
  • 用测试方法定义一个类。
  • 执行班级中的所有测试方法并检查故障。
  • 创建并执行一组测试类。

Apex 单元测试

Apex测试框架使您能够为Force.com平台上的Apex类和触发器编写和执行测试。 Apex单元测试可确保您的Apex代码的高质量,并让您满足部署Apex的要求。

测试是成功实现长期发展的关键,也是开发过程的关键组成部分。 Apex测试框架可以轻松测试您的Apex代码。 Apex代码只能在沙箱环境或开发者组织中编写,而不能在生产环境中编写。 Apex代码可以从沙箱部署到生产组织。此外,应用程序开发人员可以通过将软件包上传到Force.com AppExchange,将Apex代码从开发人员组织分发给客户。除了对质量保证至关重要之外,Apex单元测试也是部署和分销Apex的要求。以下是Apex单元测试的好处。

  • 确保您的Apex类和触发器按预期工作
  • 拥有一套可以在每次更新类和触发器时重新运行的回归测试,以确保您对应用程序进行的未来更新不会破坏现有的功能
  • 满足部署Apex生产或通过包装向客户分销Apex的代码覆盖要求
  • 高质量的应用程序交付给生产组织,使生产用户的工作效率更高
  • 高品质的应用程序交付给包用户,这增加了客户的信任

注意

在每次重大服务升级之前,Salesforce都会通过名为Apex Hammer的流程代表您运行所有Apex测试。 Hammer进程在当前版本和下一版本中运行,并比较测试结果。此过程可确保您的自定义代码中的行为未因服务升级而改变。锤子过程选择性地选择组织,并且不运行在所有组织。发现的问题是基于特定的标准进行分类的。 Salesforce致力于解决每个新版本之前发现的所有问题。

维护数据的安全性是我们的首要任务。我们不会查看或修改您的组织中的任何数据,并且所有测试都是在安全的数据中心中运行的副本中完成的。

代码覆盖要求的部署

在部署代码或将其打包为Force.com AppExchange之前,至少有75%的Apex代码必须由测试覆盖,所有这些测试都必须通过。另外,每个触发器都必须有一定的覆盖范围。尽管代码覆盖率是部署的要求,但是不要只写测试来满足这个要求。确保在您的应用中测试常见用例,包括正面和负面的测试用例,以及批量和单一记录处理。

测试方法语法

测试方法不带任何参数,并具有以下语法:

@isTest static void testName() {
    // code_block
}
或者,一个测试方法可以有这样的语法:
static testMethod void testName() {
    // code_block
}
使用isTest注释而不是testMethod关键字更灵活,因为您可以在注释中指定参数。我们稍后会介绍一个这样的参数。

测试方法的可见性并不重要,因此将测试方法声明为公共或私有并不会造成影响,因为测试框架总是能够访问测试方法。为此,语法中省略了访问修饰符。

测试方法必须在测试类中定义,这些类是用isTest注释的类。这个样本类用一种测试方法显示了一个测试类的定义。

@isTest
private class MyTestClass {
    @isTest static void myTest() {
        // code_block
    }
}
测试类可以是私有的或公共的。如果您仅使用测试类进行单元测试,则将其声明为私有。公共测试类通常用于测试数据工厂类,稍后会介绍。

单元测试示例:测试TemperatureConverter类

下面这个简单的例子是三个测试方法的测试类。正在测试的类方法以华氏温度作为输入。它将此温度转换为摄氏温度并返回转换后的结果。让我们添加自定义类和它的测试类。

  1. 在开发者控制台中,点击 File | New | Apex Class, 然后输入TemperatureConverter作为类名称,然后单击OK.
  2. 用下面的代码替换默认的类体。
    public class TemperatureConverter {
        // 拍摄华氏温度并返回摄氏温度。
        public static Decimal FahrenheitToCelsius(Decimal fh) {
            Decimal cs = (fh - 32) * 5/9;
            return cs.setScale(2);
        }
    }
  3. 按下Ctrl + S保存你的课程。
  4. 重复之前的步骤来创建TemperatureConverterTest类。添加以下这个类。
    @isTest
    private class TemperatureConverterTest {
    
        @isTest static void testWarmTemp() {
            Decimal celsius = TemperatureConverter.FahrenheitToCelsius(70);
            System.assertEquals(21.11,celsius);
        }
        
        @isTest static void testFreezingPoint() {
            Decimal celsius = TemperatureConverter.FahrenheitToCelsius(32);
            System.assertEquals(0,celsius);
        }
    
        @isTest static void testBoilingPoint() {
            Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212);        
            System.assertEquals(100,celsius,'不期望沸点温度');
        } 
        
        @isTest static void testNegativeTemp() {
            Decimal celsius = TemperatureConverter.FahrenheitToCelsius(-10);
            System.assertEquals(-23.33,celsius);
        }
          
    }
    TemperatureConverterTest测试类通过以华氏温度的不同输入调用该方法来验证该方法是否按预期工作。每种测试方法验证一种类型的输入:暖温度,冰点温度,沸点温度和负温度。验证是通过调用System.assertEquals()方法完成的,该方法有两个参数:第一个是期望值,第二个是实际值。这个方法有另一个版本,它接受第三个参数 – 一个描述比较的字符串,在testBoilingPoint()中使用。如果断言失败,则会记录此可选字符串。

让我们来运行这个类中的方法。

  1. 在开发者控制台中,点击 Test | New Run.
  2. 在Test Classes下,单击TemperatureConverterTest.
  3. 要将TemperatureConverterTest类中的所有测试方法添加到测试运行,请单击 Add Selected.
  4. 点击Run.
  5. 在“测试”选项卡中,您可以看到运行中的测试状态。展开测试运行,然后再次展开,直到看到运行的单个测试列表。他们都有绿色的选中标记。
    Inspect test results in the Developer Console

运行测试后,将自动为组织中的Apex类和触发器生成代码覆盖率。您可以在开发者控制台的“测试”标签中查看代码覆盖百分比。在这个例子中,你测试过的类,TemperatureConverter类,具有100%的覆盖率,如图所示。

View code coverage percentage in the Developer Console

注意

无论何时您修改Apex代码,请重新运行测试以刷新代码覆盖率结果。

开发人员控制台的一个已知问题是,在运行测试子集时,无法正确更新代码覆盖率。要更新代码覆盖率结果,请使用Test | Run All 而不是Test | New Run.

虽然一种测试方法会导致TemperatureConverter类的全面覆盖,但测试不同的输入以确保代码质量仍然很重要。显然,不可能验证每个数据点,但可以测试常见的数据点和不同的输入范围。例如,您可以验证传递正数和负数,边界值和无效参数值以验证负面行为。 TemperatureConverter类别的测试验证常用数据点,如沸腾温度和负温度。

TemperatureConverterTest测试等级不包括无效输入或边界条件。边界条件是关于最小值和最大值。在这种情况下,温度转换方法接受一个可以接受大于Double值的Decimal。对于无效的输入,没有无效的温度,但唯一的无效输入为空。转换方法如何处理这个值?在这种情况下,当Apex运行时将参数变量解引用以评估公式时,它会引发System.NullPointerException。您可以修改FahrenheitToCelsius()方法来检查无效输入,并在这种情况下返回null,然后添加一个测试来验证无​​效的输入行为。

到目前为止,所有的测试都通过了,因为类方法中使用的转换公式是正确的。但是那很无聊!让我们尝试模拟一个失败,看看断言失败时会发生什么。例如,让我们修改沸点温度测试,并传递沸点摄氏温度(0而不是100)的错误预期值。这导致相应的测试方法失败。

  1. 将testBoilingPoint()测试方法更改为以下。
        @isTest static void testBoilingPoint() {
            Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212);        
            // 模拟失败
            System.assertEquals(0,celsius,'不期望沸点温度');
        }
  2. 要执行相同的测试运行,请单击测试选项卡中的最新运行,然后单击 Test | Rerun.

    testBoilingPoint()中的断言失败,并引发一个致命错误(一个无法捕获的AssertException)。

  3. 通过展开最新的测试运行来检查“测试”选项卡中的结果。测试运行报告四分之一的测试失败。要获得有关失败的更多详细信息,请双击测试运行。

    详细的结果显示在单独的选项卡中,如图所示。

    Inspect results of a failed test in the Developer Console
  4. 要获取测试失败的错误消息,请双击失败测试的Errors列。你会看到以下内容。 Assertion Failed旁边的描述性文本是我们在System.assertEquals()语句中提供的文本。

    System.AssertException: Assertion Failed: 不期望沸点温度.: Expected: 0, Actual: 100.00

这些测试方法中的测试数据是数字而不是Salesforce记录。您将了解更多有关如何测试Salesforce记录以及如何在下一单元中设置数据的信息。

增加您的代码覆盖率

在编写测试时,尽可能实现最高的代码覆盖率。不要只瞄准75%的覆盖率,这是Force.com平台对部署和软件包的最低覆盖率。测试覆盖的测试用例越多,代码的健壮性就越高。有时,即使在为所有类方法编写测试方法之后,代码覆盖率也不是100%。一个常见原因是没有涵盖条件代码执行的所有数据值。例如,当你的类方法有if语句时,一些数据值往往会被忽略,这些语句会根据是否满足条件评估条件而导致不同的分支被执行。确保您的测试方法考虑到这些不同的值。

此示例包含类方法getTaskPriority(),它包含两个if语句。这种方法的主要任务是根据给定的导联状态返回一个优先级字符串值。该方法首先验证状态,如果状态无效则返回null。如果状态是CA,则方法返回“高”;否则,返回任何其他状态值的“正常”。

public class TaskUtil {
    public static String getTaskPriority(String leadState) {
        // 验证输入
        if (String.isBlank(leadState) || leadState.length() > 2) {
            return null;
        }
            
        String taskPriority;
        
        if (leadState == 'CA') {
             taskPriority = 'High'; 
        } else {
             taskPriority = 'Normal';
        }
        
        return taskPriority;
    }
}
注意

等号运算符(==)执行不区分大小写的字符串比较,因此不需要先将字符串转换为小写字母。这意味着传入’ca’或’Ca’将满足字符串字面值’CA’的相等条件。

这是getTaskPriority()方法的测试类。测试方法只需调用一个状态(’NY’)的getTaskPriority()。

@isTest
private class TaskUtilTest {
    @isTest static void testTaskPriority() {
        String pri = TaskUtil.getTaskPriority('NY');
        System.assertEquals('Normal', pri);
    }
}
让我们在开发者控制台中运行这个测试类(TaskUtilTest),并检查测试覆盖的相应TaskUtil类的代码覆盖率。测试运行结束后,TaskUtil的代码覆盖率显示为75%。如果您在开发人员控制台中打开此课程,则会看到六个蓝色(被覆盖)线条和两个红色(未被覆盖)线条,如图所示。
Lines covered for the TaskUtil class in the Developer Console

第五行没有被覆盖的原因是因为我们的测试类没有包含一个测试来传递一个无效的状态参数。同样,第11行没有被覆盖,因为测试方法没有通过“CA”作为状态。我们再添加两个测试方法来覆盖这些情况。以下显示了添加testTaskHighPriority()和testTaskPriorityInvalid()测试方法后的完整测试类。如果您重新运行此测试类,TaskUtil的代码覆盖率现在为100%!

@isTest
private class TaskUtilTest {
    @isTest static void testTaskPriority() {
        String pri = TaskUtil.getTaskPriority('NY');
        System.assertEquals('Normal', pri);
    }
    
    @isTest static void testTaskHighPriority() {
        String pri = TaskUtil.getTaskPriority('CA');
        System.assertEquals('High', pri);
    }
    
    @isTest static void testTaskPriorityInvalid() {
        String pri = TaskUtil.getTaskPriority('Montana');
        System.assertEquals(null, pri);
    }
}
创建并执行测试套件

测试套件是一起运行的Apex测试类的集合。例如,创建一套您每次准备部署时运行的测试,或者Salesforce发布新版本。在开发者控制台中设置一个测试套件来定义一组定期一起执行的测试类。

您现在在您的组织中有两个测试课程。这两个阶级是不相关的,但让我们暂时假装他们是。假设有些情况下你想运行这两个测试类,但不想运行你的组织中的所有测试。创建一个包含两个类的测试套件,然后在套件中执行测试。

  1. 在开发者控制台中,选择 Test | New Suite.
  2. 输入TempConverterTaskUtilSuite作为套件名称,然后单击OK.
  3. 选择TaskUtilTest,按住Ctrl键,然后选择TemperatureConverterTest
  4. 要将所选测试类添加到套件,请单击 >.

    Test suite editing window with two selected test classes

  5. 点击Save.
  6. 选择Test | New Suite Run.
  7. 选择TempConverterTaskUtilSuite,然后单击>将TempConverterTaskUtilSuite移动到选择的测试套件列。
  8. 点击Run Suites.
  9. 在“测试”选项卡上,监视测试运行状态。展开测试运行,然后再次展开,直到看到运行的单个测试列表。就像在单个测试方法的运行中一样,您可以双击方法名称以查看详细的测试结果。

创建测试数据

在测试方法中创建的Salesforce记录不会提交到数据库。当测试结束执行时,它们会回滚。这个回滚行为对于测试是很方便的,因为在测试执行后你不必清理你的测试数据。

默认情况下,除了访问设置和元数据对象(如User或Profile对象)外,Apex测试不能访问组织中预先存在的数据。为您的测试设置测试数据。创建测试数据可使您的测试更健壮,并防止组织中缺少或更改数据导致的故障。您可以直接在测试方法中创建测试数据,也可以使用实用程序测试课程,稍后您将会看到。

注意

尽管这样做不是最佳实践,但有时候测试方法需要访问预先存在的数据。要访问组织数据,请使用@isTest注释测试方法(SeeAllData = true)。本机中的测试方法示例不访问组织数据,因此不使用SeeAllData参数。

告诉我更多…

  • 您可以在每个组织中最多保存3 MB的Apex代码。用@isTest注释的测试类不计入此限制。
  • 即使测试数据回滚,也不会使用单独的数据库进行测试。因此,对于某些具有唯一约束的字段的sObjects,插入重复的sObject记录会导致错误。
  • 测试方法不发送电子邮件。
  • 测试方法不能调出外部服务。您可以在测试中使用模拟标注。
  • 在测试中执行的SOSL搜索返回空结果。为了确保可预测的结果,使用Test.setFixedSearchResults()来定义搜索返回的记录。