Salesforce单元测试的问题

Salesforce的单元测试是强制的,不达到一定的代码覆盖率,就不能成功部署。但有时单元测试会造成麻烦。

最近碰到一个问题,写个batch apex job。取数据的soql大致是SELECT Id, Name, Status FROM CampaignMember WHERE Status IN ('foo', 'bar')。然后根据不同的Status进行不同的操作:

  global void execute(Database.BatchableContext bc, List<CampaignMember> records) {
    for (CampaignMember r : records) {
       if (r.Status == 'FOO') { //do something
       
       } else if (r.Status == 'BAR') { //do something
       }
}

用真实数据(Salesforce里已有的数据)测试通过。

但是在写单元测试时出现了问题。因为一般来说,单元测试用的数据要自己插入,即

@IsTest
public with sharing class someTest {
  @IsTest
  public static void testFoo() {
     CampaignMember cm = new CampaignMember(Status = 'foo');
     insert cm;      
  }    
}

但测试通不过,调试发现,原来是有个触发器把Status自动改成'something'。问题是那个触发器是managed package创建的,看不到代码,不清楚它的逻辑,也不知道是谁装的。

最后只能利用CampaignMember对象里一个可写的字段,做了个hack。先把测试代码改写成

@IsTest
public with sharing class someTest {
  @IsTest
  public static void testFoo() {
     CampaignMember cm1 = new CampaignMember (Status = 'foo', SomeWriteableField = 'unitTestFoo'); 
     insert cm1;
     CampaignMember cm2 = new CampaignMember (Status = 'bar', SomeWriteableField = 'unitTestBar');
insert cm2; String query
= 'SELECT Id, Name, Status, SomeWriteableField FROM CampaignMember WHERE Id IN (\'' + cm1.Id + ',\'' + cm2.Id + '\')'; Test.startTest(); Database.executeBatch(new SomeBatchable(query), 2); Test.stopTest(); System.assert(......) } }

 

然后改写原来的处理代码:

global class SomeBatchable implements Database.Batchable<SObject>, Schedulable {
  global String query; 
  global SomeBatchable() {
    query = 'SELECT Id, Name, Status, SomeWriteableField FROM CampaignMember WHERE Status IN (\'FOO\', \'BAR\')';
  }

  global SomeBatchable(String q) {
    query = q;
  }    

  global Database.QueryLocator start(Database.BatchableContext bc) {
    return Database.getQueryLocator(query);
  }

  global void execute(Database.BatchableContext bc, List<CampaignMember> records) {
    for (CampaignMember r : records) {
       String unitTestType = '';
       try {
          if (r.SomeWriteableField == 'unitTestFoo') {
             unitTestType = 'foo';
          } else if (r.SomeWriteableField == 'unitTestBar') {
             unitTestType = 'bar';
          }
       } catch (Exception e) {//若没有取SomeWriteableField字段,会抛异常,但不用管
}        if (r.Status == 'FOO' || unitTestType == 'foo') { //do something
       } else if (r.Status == 'BAR' || unitTestType == 'bar') { //do something
       }
    }
  }
}

通过这样肮脏的hack代码,总算通过了单元测试。本来单元测试是为了保证程序没有错,但现在反而要修改程序来迁就单元测试,由此可见单元测试的垃圾的一面。

posted @ 2023-03-16 03:04  平静寄居者  阅读(46)  评论(0编辑  收藏  举报