Help reaching 100% coverage

I have a relatively simple class to add contact roles to an Opportunity after conversion. However, I cannot reach 100% code coverage and I really can’t figure it out.

Here’s my code:

Trigger:

trigger Opportunities on Opportunity (after insert) {

    Opportunities o = new Opportunities();
    o.SetContactRoleDefaults(Trigger.new);     
}

Class:

public class Opportunities {

    public Opportunities()
    {
    }

    public void SetContactRoleDefaults(Opportunity[] opptys) 
    {
        set<ID> set_opptyIDs = new set<ID>();

        for(Opportunity o:opptys) { 
            set_opptyIDs.add(o.id);
        }

        list<OpportunityContactRole> list_opptyContactRolesToUpdate = new list<OpportunityContactRole>();
        for(OpportunityContactRole ocr:[select Id,IsPrimary,Role from OpportunityContactRole where OpportunityId in :set_opptyIDs]) { 
            **ocr.IsPrimary = true;
            ocr.Role = 'Decision Maker';
            list_opptyContactRolesToUpdate.add(ocr);**
        }

        if (list_opptyContactRolesToUpdate.size() > 0) {
            **update list_opptyContactRolesToUpdate;**
        }

    }
}

Test class:

@isTest
private class Opportunities_Test {

    static testMethod void SetContactRoleDefaults_Test() {

        Lead myLead = new Lead(FirstName = 'Fred', LastName = 'Fry', Company='Fry And Sons');
        insert myLead;

        Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(myLead.id);

        LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);

        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());

        List<Opportunity> opps = new List<Opportunity>([
            SELECT Name, Id
            FROM Opportunity
            WHERE Name = 'Fry And Sons'
        ]);

        for (Opportunity o :opps)
            system.assertEquals('Fry And Sons', o.Name);

        List<Contact> conts = new List<Contact>([
            SELECT Id, Name
            FROM Contact
            WHERE Name = 'Fred Fry'
        ]);

        List<OpportunityContactRole> oppContacts = new List<OpportunityContactRole>([
            SELECT ContactId, OpportunityId, Role, IsPrimary
            FROM OpportunityContactRole
            WHERE ContactId IN :conts
            AND OpportunityId IN :opps
        ]);  

        for (OpportunityContactRole ocr :oppContacts) {
            system.assertEquals('Decision Maker', ocr.Role);
            system.assertEquals(true, ocr.IsPrimary);
        }        
    }     
}

Any ideas?

Answer

This is an order of execution issue I believe, though I’m really struggling to find any documentation on exactly how this works.

The docs for the lead conversion additional settings state that if triggers are enabled for lead convert and the opportunity has before triggers, these fire before the opportunity contact roles are created, though there is no information about what happens to the after triggers.

I’ve managed to get 100% code coverage by moving the contact role update code into an @future method – this runs after the lead convert transaction has completed so the role object are guaranteed to be inserted:

public class Opportunities {

public Opportunities()
{
}

public void SetContactRoleDefaults(Opportunity[] opptys) 
{
    set<ID> set_opptyIDs = new set<ID>();

    for(Opportunity o:opptys) { 
        set_opptyIDs.add(o.id);
    }

    AsynchContactRoleDefaults(set_opptyIds);
}

@future
public static void AsynchContactRoleDefaults(Set<Id> set_opptyIDS)
{

    list<OpportunityContactRole> list_opptyContactRolesToUpdate = new list<OpportunityContactRole>();
    for(OpportunityContactRole ocr:[select Id,IsPrimary,Role from OpportunityContactRole where OpportunityId in :set_opptyIDs]) { 
        ocr.IsPrimary = true;
        ocr.Role = 'Decision Maker';
        list_opptyContactRolesToUpdate.add(ocr);
    }

    if (list_opptyContactRolesToUpdate.size() > 0) {
        update list_opptyContactRolesToUpdate;
    }

}
}

The other change I’ve made is to wrap the convert in start/stoptest calls – this forces the @future method to fire in the test context:

@isTest
private class Opportunities_Test {

    static testMethod void SetContactRoleDefaults_Test() {

        Lead myLead = new Lead(FirstName = 'Fred', LastName = 'Fry', Company='Fry And Sons');
        insert myLead;

        Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(myLead.id);

        LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
        lc.setConvertedStatus(convertStatus.MasterLabel);

        Test.startTest();
        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());
        Test.stopTest();

        List<Opportunity> opps = new List<Opportunity>([
            SELECT Name, Id
            FROM Opportunity
            WHERE Name = 'Fry And Sons'
        ]);

        for (Opportunity o :opps)
            system.assertEquals('Fry And Sons', o.Name);

        List<Contact> conts = new List<Contact>([
            SELECT Id, Name
            FROM Contact
            WHERE Name = 'Fred Fry'
        ]);

        List<OpportunityContactRole> oppContacts = new List<OpportunityContactRole>([
            SELECT ContactId, OpportunityId, Role, IsPrimary
            FROM OpportunityContactRole
            WHERE ContactId IN :conts
            AND OpportunityId IN :opps
        ]);  

        for (OpportunityContactRole ocr :oppContacts) {
            system.assertEquals('Decision Maker', ocr.Role);
            system.assertEquals(true, ocr.IsPrimary);
        }        
    }     
}

Attribution
Source : Link , Question Author : Davin Casey , Answer Author : Bob Buzzard

Leave a Comment