Apex单元测试

单元测试类

Salesforce中为Apex语言提供了完整的单元测试流程,包括单元测试类、测试的运行和结果分析等。

单元测试类是一种特殊的Apex类,基本语法和普通的Apex类一样。

单元测试类的结构是:

@isTest
private class MyTestClass {
    @isTest 
    static void myTest() {
        // Test
    }
}

可以看到,“@isTest”是一个关键的注解,带有它的类和方法会被系统认定为单元测试的类和方法。

对于单元测试的方法,可以用“testMethod”关键字代替“@isTest”注解,比如:

static testMethod void myTest() {
    // Test
}

单元测试的方法必须定义在单元测试类中。

单元测试类和方法的访问控制权限并不重要。无论是定义为public还是private,系统都可以进入其中并执行测试代码。

断言函数

系统中提供了一组断言函数来进行结果的比较。它们主要包括:

  • System.assert(condition, msg):用于判断某条件是否为真,如果不为真则给出错误信息
  • System.assertEquals(expected, actual, msg):用于判断期望的值是否和实际的值相同,如果不同则给出错误信息
  • System.assertNotEquals(expected, actual, msg):用于判断期望的值是否和实际的值不同,如果相同则给出错误信息

单元测试示例

在Developer Console中,可以新建两个Apex类,一个作为正常的类,另一个作为单元测试类使用。

正常的类中写入如下代码,将美元转化为欧元,汇率取0.9:

public class CurrencyConverter {
    public static Decimal GetEuroFromDollar(Decimal dollar) {
        Decimal euro = dollar * 0.9;
        return euro;
    }
}

在单元测试类中写入如下代码,测试函数的执行情况:

@isTest
private class CurrencyConverterTest {
    @isTest
    static void testGetEuroFromDollar() {
        Decimal euro = CurrencyConverter.GetEuroFromDollar(100);
        System.assertEquals(90, euro);
    }
}

在Developer Console中,可以直接点击单元测试类窗口右上角的“Run Test”按钮,则类中的测试方法会被自动执行,在窗口下方的控制台中会显示结果。“Logs”标签中会显示执行测试的日志,“Tests”标签中会显示哪些测试函数被执行以及执行结果。

代码覆盖率

Salesforce非常注重代码的覆盖率。系统规定的最低代码覆盖率是75%,也就是说每一个类的单元测试的范围要包括被测试的类的至少75%的代码。

在Developer Console中,当执行完一个单元测试类的所有测试之后,打开被测试的类,在编辑区域的左上方会有“Code Coverage”按钮,点击即可看到代码覆盖率。在下方“Tests”部分的右侧是所有类的覆盖率一览。

单元测试中的数据

在单元测试中,有时候需要新建对象数据或修改对象数据。所有单元测试中的数据都是独立于实际数据库的。

在单元测试开始的时候,默认为数据库是空的,不能直接从中读取已经存在的数据,必须手动新建。

当单元测试结束时,所有往数据库中增加、修改的数据都会被清理掉。

注意:虽然单元测试的数据独立于实际数据库,但是在单元测试中的数据也会暂时被保存在数据库中。所以如果在单元测试中新建了某条记录,而此记录的某些字段违反了验证规则,或者某些数据必须唯一的字段和显存的某些记录相同,系统会报错,测试无法继续进行。

比如:系统中设置了验证规则:所有“Account”对象的名字值是唯一的,并且已经存在了一个叫“Test Account”的对象,那么在测试类中新建一个叫“Test Account”的对象,则系统会报错。

设置测试数据

如果一个单元测试类中包含若干测试函数,而这些函数会用相同的一组数据,则可以使用“testSetup”注解定义单元测试类的初始化函数。

在初始化函数中建立的测试数据可以供每一个单元测试函数使用,并且在测试函数中对于数据库的更改并不会带到其他测试函数中,所以每一个测试函数在运行时,数据库中的状态都和执行完初始化函数的状态一样。

示例代码:

@isTest
private class ExampleTestSetup {

    // 使用testSetup定义初始化函数
    @testSetup 
    static void setup() {
        List<Account> testAccts = new List<Account>();
        for(Integer i=0;i<2;i++) {
            testAccts.add(new Account(Name = 'TestAcct'+i));
        }
        insert testAccts;        
    }
    
    @isTest 
    static void testMethod1() {
        // 在setup()函数中插入数据库的testAccts对象可以在这里直接使用,并且其他测试函数对数据的更改不会在此函数中产生作用

        Account acct = [SELECT Id FROM Account WHERE Name='TestAcct0' LIMIT 1];
        acct.Phone = '555-1212';
        update acct;
        
        // ...        
    }

    @isTest 
    static void testMethod2() {
        // 在setup()函数中插入数据库的testAccts对象可以在这里直接使用,并且其他测试函数对数据的更改不会在此函数中产生作用
        // ... 
    }

}

单元测试的限制

单元测试类中,有若干限制:

  • 系统无法发送邮件
  • 系统无法和外部的网络服务通讯,所以无法通过调用web service得到数据,但是可以自己建立模拟数据
  • 无法使用SOSL查询,但是可以使用Test.setFixedSearchResults()方法来自己建立模拟的查询结果
posted @ 2017-11-17 04:56  程程哥  阅读(1143)  评论(0编辑  收藏  举报