function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Dave BlumenfeldDave Blumenfeld 

Null Pointer Exception on Campaign Member Attribution Trigger

Hi All.  I am trying to write an apex trigger that writes a few fields that serve as "last touch attribution" on a lead or contact onto a campaign member so that on any given campaign we can track things like what the source channel that particular campaign response is from.  I wrote a trigger that seems to be working great for both individual and bulk updates, but am having trouble with the Test Class.  (a bit of background..I am actually a digital marketer who got lassooed into being the Salesforce guy, and have little to no coding experience and am a newbie so if this looks stupid try and use small words to help me understand haha. )

I am running into an issue with the error below:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AppendLastTouchCampaignMembers: execution of BeforeInsert

caused by: System.NullPointerException: Attempt to de-reference a null object

Trigger.AppendLastTouchCampaignMembers: line 26, column 1: []

First it was appearing in line twenty five (the "if" statement which said if( cm.contactId == null).  When I changed it to string.isBlank(cm.ContactId) it moved down to line 26.

Trigger:
trigger AppendLastTouchCampaignMembers on CampaignMember (before insert) {
    
    Map<ID, Lead> myLead = new Map<ID, Lead>();
    Map<ID, Contact> myContact = new Map<ID, Contact>();
    Set<Id> leadIds = new Set<Id>();
    Set<Id> contactIds = new Set<Id>();
    

    for (CampaignMember cm : Trigger.new) {

        if (cm.ContactId == null){
            leadIds.add(cm.LeadId);
        }
        else{
            contactIds.add(cm.ContactId);
        }
    }
    
    myLead = new Map<ID, Lead>([SELECT id, utm_source__c, utm_medium__c, utm_term__c FROM Lead WHERE ID IN :leadIds]);
    myContact = new Map<Id, Contact>([SELECT id, utm_source__c, utm_medium__c, utm_term__c FROM Contact WHERE ID IN :contactIds]);
    
    
    for (CampaignMember cm : Trigger.new){
        if (String.isBlank(cm.ContactId)) {
            Lead myCM = myLead.get(cm.LeadId);
            cm.Last_Touch_Source__c = myCM.utm_source__c;
            cm.Last_Touch_Medium__c = myCM.utm_medium__c;
            cm.Last_Touch_Term__c = myCM.utm_term__c;
        }
        else{
            Contact myCM = myContact.get(cm.ContactId);
            cm.Last_Touch_Source__c = myCM.utm_source__c;
            cm.Last_Touch_Medium__c = myCM.utm_medium__c;
            cm.Last_Touch_Term__c = myCM.utm_term__c;
        }
    }
}

Test Class
@isTest 

public class TestCampaignAttributionTrigger {
    static testMethod void TestCampaignMember (){

        Test.startTest();

        //Creates Contact to be linked to Campaign Member
        Contact testContact = new Contact(FirstName = 'TestContactF', LastName = 'TestContactL', Email = 'none@navinet.net', utm_source__c = 'discover', utm_medium__c = 'bought database', utm_term__c = 'test');
        Lead testLead = new Lead(FirstName = 'Dave', LastName = 'Blum', Company = 'DaveCorp', Email = 'dblum@xl.com', utm_source__c = 'discover', utm_medium__c = 'bought database', utm_term__c = 'test');
        insert testContact;
        insert testLead;



        //Creates a new campaign
        Campaign c = new Campaign(Name='Test', Status='In Progress');
        insert c;
        
        //Assign Lead & Contact to campaign
        CampaignMember newMember2 = 
        new CampaignMember(Campaign = [SELECT Id FROM Campaign WHERE Status = 'In Progress' LIMIT 5], Lead = testLead);
        insert newMember2;
        
        CampaignMember newMember = 
        new CampaignMember(Campaign = [SELECT Id FROM Campaign WHERE Name = 'Test' LIMIT 5], Contact = testContact);
        insert newMember;

        Test.stopTest();

    }
}

 
Dave BlumenfeldDave Blumenfeld
Update...I seem to have solved it with this TestClass for 100% code coverage....dunno if anything is still fishy though, so please feel free to peruse and comment! 
 
@isTest 

public class TestCampaignAttributionTrigger {
    static testMethod void TestCampaignMember (){

        Test.startTest();

        //Creates Contact to be linked to Campaign Member
        Contact testContact = new Contact(FirstName = 'TestContactF', LastName = 'TestContactL', Email = 'none@navinet.net', utm_source__c = 'discover', utm_medium__c = 'bought database', utm_term__c = 'test');
        Lead testLead = new Lead(FirstName = 'Dave', LastName = 'Blum', Company = 'DaveCorp', Email = 'dblum@xl.com', utm_source__c = 'discover', utm_medium__c = 'bought database', utm_term__c = 'test');
        insert testContact;
        insert testLead;



        //Creates a new campaign
        Campaign c = new Campaign(Name='Test', Status='In Progress');
        insert c;
        
        //Assign Lead & Contact to campaign
        CampaignMember newMember2 = 
        new CampaignMember(Campaign = [SELECT Id FROM Campaign WHERE Status = 'In Progress' LIMIT 5], Lead = testLead, LeadId = testLead.Id, CampaignId = c.Id);
        
        CampaignMember newMember = 
        new CampaignMember(Campaign = [SELECT Id FROM Campaign WHERE Name = 'Test' LIMIT 5], Contact = testContact, ContactId = testContact.Id, CampaignId = c.Id);
        
        insert newMember2;
        insert newMember;

        Test.stopTest();

    }
}