You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Salesforce单元测试失败求助:CountCasesOfContact类测试问题排查

Salesforce单元测试失败排查求助

我是Salesforce新手,正在学习单元测试。为CountCasesOfContact类编写的单元测试始终失败,目前连插入事件的测试都无法通过,恳请协助排查问题。以下是我的类代码与单元测试代码:

原CountCasesOfContact类代码

public class CountCasesOfContact {
    private List<Case> caseList;
    private List<Case> oldList;

    public static void countCases(List<Case> caseList, List<Case> oldList){

        Map<Id, Contact> contactsToUpdate = new Map<Id, Contact>();

        //Run the trigger for all after events, check if object has trigger.new and/or trigger.old and collect parent object and it's id in a map
        if(Trigger.isAfter && Trigger.new != null){
                for(Case cs: caseList) {
                    contactsToUpdate.put(cs.ContactId, new Contact(Id=cs.ContactId,Open_Cases_Count__c=0, Closed_Cases_Count__c = 0));
                }
        }
        if(Trigger.isAfter && Trigger.old != null) {
            for(Case cs: oldList) {
                contactsToUpdate.put(cs.ContactId, new Contact(Id=cs.ContactId,Open_Cases_Count__c=0, Closed_Cases_Count__c = 0));
            }
        }

        //remove null id-contact pairs from map
        contactsToUpdate.remove(null); 
        
        //Get count result of open/closed Cases for each contact and set the value to related fields
        for(AggregateResult result: [SELECT COUNT(Id) caseCount, ContactId ContactId FROM Case WHERE Status = 'Closed' AND ContactId = :contactsToUpdate.keySet() GROUP BY ContactId] ) {
            contactsToUpdate.get((Id)result.get('ContactId')).Closed_Cases_Count__c=(Integer)result.get('caseCount');
        }
        for(AggregateResult result: [SELECT COUNT(Id) caseCount, ContactId ContactId FROM Case WHERE Status != 'Closed' AND ContactId = :contactsToUpdate.keySet() GROUP BY ContactId] ) {
            contactsToUpdate.get((Id)result.get('ContactId')).Open_Cases_Count__c=(Integer)result.get('caseCount');
        }
        update contactsToUpdate.values();
    }
}

原单元测试代码

@isTest
public class CountCasesOfContactTest {
@isTest
    private static void countCasesTestInsert(){
        
        Test.startTest();
        Contact ct = new Contact(LastName = 'Test Contact', Open_Cases_Count__c = 0, Closed_Cases_Count__c = 0);
        insert ct;

        Case cs = new Case(ContactId = ct.id, Subject = 'Test Case', Status = 'New', Origin = 'Phone');
        insert cs;
        
        CountCasesOfContact.countCases([Select id From Case], null);
        Test.stopTest();

        Contact cnt = [SELECT id, Open_Cases_Count__c, Closed_Cases_Count__c FROM Contact];
        system.assertEquals(1, cnt.Open_Cases_Count__c);
        system.assertEquals(0, cnt.Closed_Cases_Count__c);
    }
}

问题排查与修正方案

核心问题点

  1. 依赖Trigger上下文导致逻辑不执行:原类中Trigger.isAfter在单元测试直接调用方法时为false,导致收集关联ContactId的代码块完全跳过,后续更新逻辑根本无法触发。
  2. 查询Case时缺少ContactId字段:测试代码中调用方法时传入的[Select id From Case]未包含ContactId,遍历Case列表时cs.ContactId为null,即使Trigger逻辑生效,也会被contactsToUpdate.remove(null)清空。
  3. Contact查询无明确条件:测试中查询Contact时未指定Id,若测试环境存在其他Contact数据,会导致查询结果异常。

修正后的类代码

移除对Trigger.isAfter的依赖,让方法专注于处理传入的Case列表关联的Contact:

public class CountCasesOfContact {
    public static void countCases(List<Case> caseList, List<Case> oldList){
        Map<Id, Contact> contactsToUpdate = new Map<Id, Contact>();

        // 收集所有非空的关联ContactId
        if(caseList != null){
            for(Case cs: caseList) {
                if(cs.ContactId != null){
                    contactsToUpdate.put(cs.ContactId, new Contact(Id=cs.ContactId, Open_Cases_Count__c=0, Closed_Cases_Count__c = 0));
                }
            }
        }
        if(oldList != null) {
            for(Case cs: oldList) {
                if(cs.ContactId != null){
                    contactsToUpdate.put(cs.ContactId, new Contact(Id=cs.ContactId, Open_Cases_Count__c=0, Closed_Cases_Count__c = 0));
                }
            }
        }
        
        // 更新Contact的案件计数
        for(AggregateResult result: [SELECT COUNT(Id) caseCount, ContactId ContactId FROM Case WHERE Status = 'Closed' AND ContactId = :contactsToUpdate.keySet() GROUP BY ContactId] ) {
            contactsToUpdate.get((Id)result.get('ContactId')).Closed_Cases_Count__c=(Integer)result.get('caseCount');
        }
        for(AggregateResult result: [SELECT COUNT(Id) caseCount, ContactId ContactId FROM Case WHERE Status != 'Closed' AND ContactId = :contactsToUpdate.keySet() GROUP BY ContactId] ) {
            contactsToUpdate.get((Id)result.get('ContactId')).Open_Cases_Count__c=(Integer)result.get('caseCount');
        }
        update contactsToUpdate.values();
    }
}

修正后的测试代码

确保传入包含ContactId的Case列表,且查询Contact时指定明确条件:

@isTest
public class CountCasesOfContactTest {
    @isTest
    private static void countCasesTestInsert(){
        Test.startTest();
        Contact ct = new Contact(LastName = 'Test Contact', Open_Cases_Count__c = 0, Closed_Cases_Count__c = 0);
        insert ct;

        Case cs = new Case(ContactId = ct.id, Subject = 'Test Case', Status = 'New', Origin = 'Phone');
        insert cs;
        
        // 传入包含ContactId的Case列表
        CountCasesOfContact.countCases([SELECT Id, ContactId FROM Case WHERE Id = :cs.Id], null);
        Test.stopTest();

        // 通过ContactId精准查询,避免数据干扰
        Contact cnt = [SELECT Id, Open_Cases_Count__c, Closed_Cases_Count__c FROM Contact WHERE Id = :ct.Id];
        System.assertEquals(1, cnt.Open_Cases_Count__c);
        System.assertEquals(0, cnt.Closed_Cases_Count__c);
    }
}

内容的提问来源于stack exchange,提问作者627

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:38:10