I've started a new job and the test code coverage here is poor.

I am working to improve this and one of the batch classes has coverage of 77% in production. This is now below the org % so I thought I'd get a quick win.

The Full sandbox was refreshed recently so I go to see if I can fix the 3 lines not being tested. Looks easy.


In Full the coverage is 27%. The classes are identical. The scheduled classes are identical. The test classes are identical (I even removed all my debug messages)

In Full it seems that the tests stop at the Execute() method. Debug logs show that everything up to that point works fine, test Leads are inserted. IDs correspond at each end of the process.

What am I missing? Why would tests be better in Prod than in Sandbox?


GLOBAL CLASS Update_IC_CampaignBatch implements Database.Batchable < SObject > {
    GLOBAL Database.queryLocator start(Database.BatchableContext ctx) {
        String lsStatus = 'ICReady';
        string query = 'SELECT id,Name from Lead WHERE status=:lsStatus'  ;
        RETURN database.getQueryLocator(query);
    GLOBAL VOID execute(Database.BatchableContext BC, List < Lead > scope) {
        Set<ID> leadIDs= new Set<ID>();
        for(Lead l: scope){
        Set<ID> campaignIDs = new Set<ID>();
        for(CampaignMember cm : [SELECT CampaignID, LeadID, Status FROM CampaignMember WHERE LeadID IN : leadIDs]){
        list<Campaign> listCampaign = new list<Campaign>();
        for(Campaign c : [select Id, Status from Campaign where Id IN : campaignIDs ]){
            c.Status = 'IC Daily Campaign Ready';

        if(listCampaign.size() > 0){
            update listCampaign;

    GLOBAL VOID finish(Database.BatchableContext BC) {


Test Class:

public class Update_IC_CampaignBatch_Test {
    static testMethod void runBatch() {

        Campaign newCmp = NEW Campaign();
        newCmp.Name ='TestName';
        newCmp.Accommodation__c = 'test';
        newCmp.IsActive = True;
        insert newCmp;
        Campaign cmp = [SELECT Id, Name FROM Campaign WHERE Name = 'TestName' LIMIT 1 ];

        Lead L1 = new Lead();
        L1.lastname = 'Last';
        L1.firstname = 'First';
        L1.company = 'Company ABC';
        L1.leadsource = 'Matching Campaign';
        L1.IC_Campaign_Eligible__c = TRUE;
        insert L1;
        Lead testLead= [SELECT Id, Name FROM Lead WHERE Name = 'First Last' LIMIT 1];

        List<CampaignMember> testCampMemb1 = new List<CampaignMember>();
        testCampMemb1.add(new CampaignMember(LeadId = testLead.Id , CampaignId = cmp.Id, Status = 'Eligible Planned Send'));
        system.debug('\n SGTEST testCampMemb1===>'+testCampMemb1);

        if (!testCampMemb1.isEmpty()) {
              Database.executeBatch(new Update_IC_CampaignBatch(), 1);            
  • 1
    Coverage stopping at execute() is a good indicator that the query in start() is not matching anything. Can you include some relevant code elements here?
    – David Reed
    Nov 28, 2018 at 18:43
  • 2
    Is your test class using seeAllData=true? Nov 28, 2018 at 18:44
  • 1
    I think you are going to have to include some relevant code or this question is not answerable.
    – Adrian Larson
    Nov 28, 2018 at 18:48
  • No - SeeAllData is not used
    – SeanGorman
    Nov 28, 2018 at 18:52
  • 2
    The first thing that comes to my mind is the potential for a workflow rule + field update, or a Process Builder, or a trigger on Lead or CampaignMember that is altering your test lead's status. At this point, I think your best option is to perform a diff between your full & prod orgs to find the difference in metadata (and there must be some difference). If you don't have up-to-date local copies of your org metadata or aren't using source control, sforgcompare.herokuapp.com can help you with this.
    – Derek F
    Nov 28, 2018 at 19:05

1 Answer 1


You forgot to insert testCampMemb1; before you started the batch, so it didn't exist in the database. You also have some questionable code that you could remove (if (!testCampMemb1.isEmpty()) { and if(listCampaign.size() > 0){, for example).

  • Hi Fox - yes that is exactly why the 3 lines don't test - hence why I thought it was a quick win.
    – SeanGorman
    Nov 28, 2018 at 19:15
  • What is specifically questionable about those lines? Are you saying they are not required?
    – SeanGorman
    Nov 28, 2018 at 19:37
  • 2
    @SeanGorman (a) the unit test if statement is logically impossible. This would give a seasoned programmer pause to consider why this code exists. You would do well to avoid writing logically impossible if statements when possible. (b) the execute method if statement is an unnecessary guard, and has been for years now. It simply clutters up code without any benefit. An empty list DML uses no extra CPU time or governor limits as opposed to checking the list yourself (meaning, the if statement actually wastes time).
    – sfdcfox
    Nov 28, 2018 at 19:58
  • I just want to highlight for others - though this is the fix that I was trying to apply, it doesn't answer the question. Despite this, Fox, you are a scholar and a gentleman as always.
    – SeanGorman
    Nov 29, 2018 at 16:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .