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

Salesforce部署Apex触发器沙箱覆盖率57%生产报0%问题排查

Apex触发器部署报0%代码覆盖率问题修复

你遇到的部署报错核心是测试类本身运行失败、触发器逻辑存在缺陷,沙箱显示的57%覆盖率是历史测试缓存导致的无效数据,生产部署时会重新执行所有测试,测试失败的类对应代码覆盖率直接计为0。具体问题点和修复方案如下:

  • 触发器逻辑缺陷:触发器仅绑定了before insert时机,但代码里直接调用Trigger.oldMap.get(leadObj.Id),insert场景下Trigger.oldMap本身为null,执行到这行直接抛空指针异常;且你的逻辑是判断字段变更后计算值,字段变更只存在于update场景,原触发时机配置错误。
  • 测试类致命错误:你在测试方法里new了Lead对象后,没有先执行insert操作就直接调用update,DML操作要求update的记录必须存在有效Id,这行代码会直接抛DML异常,整个测试方法执行失败,根本不会覆盖到触发器代码。
  • 测试类写法不规范:手动给新建的Lead对象设置Elapsed_Time__c这类触发器计算的字段是无效操作,且整个测试方法没有任何断言逻辑,不符合Salesforce测试类的强制规范。

第一步:修正触发器代码

调整触发时机为before insert, before update,增加场景判断避免空指针,覆盖插入时首次赋值、更新时字段变更两个场景:

trigger Business_Hours on Lead (before insert, before update) {
    // 查询默认营业时间配置
    BusinessHours defaultBH = [SELECT Id FROM BusinessHours WHERE IsDefault = true LIMIT 1];
    if(defaultBH != null){
        for(Lead leadObj : Trigger.new){
            Boolean needCalc = false;
            // 插入场景:只要Call_Made__c有值就计算
            if(Trigger.isInsert){
                needCalc = leadObj.Call_Made__c != null;
            }
            // 更新场景:Call_Made__c有值且发生变更才计算
            if(Trigger.isUpdate){
                needCalc = leadObj.Call_Made__c != null 
                    && Trigger.oldMap.get(leadObj.Id).Call_Made__c != leadObj.Call_Made__c;
            }
            if(needCalc){
                Decimal diffMs = BusinessHours.diff(defaultBH.Id, leadObj.CreatedDate, leadObj.Call_Made__c);
                // 毫秒转分钟,保留4位小数
                leadObj.Elapsed_Time__c = (diffMs / 60000).setScale(4);
            }
        }
    }
}

第二步:重写合规测试类

测试类里自行构造测试用营业时间数据,避免依赖不同环境的现有配置,分别覆盖插入、更新两个触发场景,增加断言验证逻辑正确性:

@isTest
public class Business_Hours_Test {
    @testMethod
    static void testInsertLeadWithCallMade() {
        // 构造测试用默认营业时间,不依赖组织现有配置
        BusinessHours testBH = new BusinessHours(
            Name = 'Test BH',
            IsDefault = true,
            MondayStartTime = Time.newInstance(9,0,0,0),
            MondayEndTime = Time.newInstance(18,0,0,0),
            TuesdayStartTime = Time.newInstance(9,0,0,0),
            TuesdayEndTime = Time.newInstance(18,0,0,0),
            WednesdayStartTime = Time.newInstance(9,0,0,0),
            WednesdayEndTime = Time.newInstance(18,0,0,0),
            ThursdayStartTime = Time.newInstance(9,0,0,0),
            ThursdayEndTime = Time.newInstance(18,0,0,0),
            FridayStartTime = Time.newInstance(9,0,0,0),
            FridayEndTime = Time.newInstance(18,0,0,0)
        );
        insert testBH;

        // 构造测试Lead,设置Call_Made时间为创建后1小时(工作时间内)
        Lead testLead = new Lead(
            LastName = 'Test',
            FirstName = 'Test',
            Company = 'ABC',
            Brand__c = 'Rain'
        );
        DateTime createTime = DateTime.newInstance(2024, 1, 2, 9, 0, 0); // 2024年1月2日周二9点
        testLead.CreatedDate = createTime;
        testLead.Call_Made__c = createTime.addHours(1); // 10点,间隔60分钟

        Test.startTest();
        insert testLead;
        Test.stopTest();

        // 验证计算结果正确
        Lead res = [SELECT Elapsed_Time__c FROM Lead WHERE Id = :testLead.Id];
        System.assertEquals(60, res.Elapsed_Time__c.setScale(0), '插入场景时间计算错误');
    }

    @testMethod
    static void testUpdateLeadCallMade() {
        // 构造测试营业时间
        BusinessHours testBH = new BusinessHours(
            Name = 'Test BH2',
            IsDefault = true,
            MondayStartTime = Time.newInstance(9,0,0,0),
            MondayEndTime = Time.newInstance(18,0,0,0),
            TuesdayStartTime = Time.newInstance(9,0,0,0),
            TuesdayEndTime = Time.newInstance(18,0,0,0),
            WednesdayStartTime = Time.newInstance(9,0,0,0),
            WednesdayEndTime = Time.newInstance(18,0,0,0),
            ThursdayStartTime = Time.newInstance(9,0,0,0),
            ThursdayEndTime = Time.newInstance(18,0,0,0),
            FridayStartTime = Time.newInstance(9,0,0,0),
            FridayEndTime = Time.newInstance(18,0,0,0)
        );
        insert testBH;

        // 先插入不带Call_Made值的Lead
        Lead testLead = new Lead(LastName='Test2', FirstName='Test2', Company='ABC2', Brand__c='Rain');
        insert testLead;
        DateTime createTime = testLead.CreatedDate;

        // 更新Call_Made字段触发更新逻辑
        testLead.Call_Made__c = createTime.addMinutes(30);
        Test.startTest();
        update testLead;
        Test.stopTest();

        // 验证结果
        Lead res = [SELECT Elapsed_Time__c FROM Lead WHERE Id = :testLead.Id];
        System.assertEquals(30, res.Elapsed_Time__c.setScale(0), '更新场景时间计算错误');
    }
}

部署前检查

  • 在沙箱中清除旧的测试缓存,重新运行Business_Hours_Test类,确认触发器代码覆盖率达到100%,所有测试用例通过
  • 部署时选择运行指定测试,勾选Business_Hours_Test,避免其他无关测试类失败影响本次部署

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:30:54