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
Brian FordBrian Ford 

Test class coverage

I have a trigger on the opportunity that requires at least 3 contact roles to be associated with any opportunity moving to a closed stage. I've created a test class for the trigger but it's not covering the try {} catch {} statements in my class.

The try{} statement should fail and the catch (exception) should be run. Need help troubleshooting.

Trigger:
trigger RequireContactRoles on Opportunity (before insert, before update) {
    
    List<Opportunity> oppsToProcess = new List<Opportunity>();

    // figure out which opportunities have transitioned to meet criteria
    for (Opportunity opp : trigger.new) {
       // check if transitioned to closed/won, otherwise ignore
       if ( (opp.StageName == '5- Closed' || opp.StageName == '6- Win') && ( trigger.oldMap.get(opp.id).StageName != '6- Win' || trigger.oldMap.get(opp.id).StageName != '5- Closed') && (opp.Override_Contact_Req__c = FALSE) ) {
          oppsToProcess.add(opp);
       }
    }

    Map<Id, Integer> ocrCountByOppId = new Map<Id, Integer>();
    
    List<AggregateResult> aggs = [SELECT OpportunityId oppId, count(id) idCount FROM OpportunityContactRole GROUP BY OpportunityId];

    for (AggregateResult ar : aggs) {
        ocrCountByOppId.put((Id) ar.get('oppId'), (Integer) ar.get('idCount'));
    }

    for (Opportunity opp : oppsToProcess) {
       Integer ocrCount = ocrCountByOppId.get(opp.id);
       if (ocrCount == null || ocrCount < 3) {
           opp.addError(' You need at least 3 contact roles to close the opportunity');
        }
    }
}

Test Class:
@isTest(SeeAllData=true)
public class RequireContactRolesTEST {
    
    static testMethod void testContactRole() {

        //create an account
        Account acc = new Account();
        acc.Name = 'Acc-ContactRoles';
        acc.BillingCountry = 'United States';
        insert acc;
		
        //create 2 contacts
        List<Contact> cons = new List<Contact>();
        
        Contact con1 = new Contact();
        con1.FirstName = 'ContactRoles1';
        con1.LastName = 'Surname1';
        con1.AccountId = acc.Id;
        cons.add(con1);
        
        Contact con2 = new Contact();
        con2.FirstName = 'ContactRoles2';
        con2.LastName = 'Surname2';
        con2.AccountId = acc.Id;
        cons.add(con2);
        insert cons;
        
        //create product
		Product2 prod = new Product2();
        prod.Name = 'contact role prod';
        prod.isActive = true;
        insert prod;
        
        //create pricebookentry
        List<Pricebook2> pb = [SELECT Id, Name, IsStandard, IsActive FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
            for (Pricebook2 pricebook : pb) {
                if (!pricebook.isActive) {
                    pricebook.isActive = true;
                }
            }
        
        PricebookEntry pbe = new PricebookEntry();
        pbe.Pricebook2Id = pb[0].id;
        pbe.Product2Id = prod.id;
        pbe.UnitPrice = 400;
        pbe.UseStandardPrice = false;
        pbe.IsActive = true;
        insert pbe;
            
        //create campaign for required opp field
        Campaign cam = new Campaign();
        cam.Name = 'cam - contact role test';
        insert cam;

        //create an opportunity
        Opportunity opp = new Opportunity();
        opp.Name = 'Opp-ContactRoles';
        opp.AccountId = acc.Id;
        opp.StageName = 'S- Suspect';
        opp.Amount = 10000;
        opp.New_Renew__c = 'New';
        opp.Campaign_Source__c = cam.Id;
        opp.CloseDate = System.Today();
        insert opp;
        
        OpportunityLineItem oli = new OpportunityLineItem();
        oli.OpportunityId = opp.id;
        oli.PricebookEntryId = pbe.id;
        oli.Quantity = 1;
        oli.UnitPrice = 250;
        insert oli;
        
        //add 2 contact roles and make 1 the primary
        List<OpportunityContactRole> conRoles = new List<OpportunityContactRole>();
        
        OpportunityContactRole ocr1 = new OpportunityContactRole();
        ocr1.OpportunityId = opp.Id;
        ocr1.ContactId = con1.Id;
        ocr1.Role = 'Buyer';
        ocr1.IsPrimary = TRUE;
        conRoles.add(ocr1);

        OpportunityContactRole ocr2 = new OpportunityContactRole();
        ocr2.OpportunityId = opp.Id;
        ocr2.ContactId = con2.Id;
        ocr2.Role = 'Tester';
        ocr2.IsPrimary = FALSE;
        conRoles.add(ocr2);
        insert conRoles;        
           
        try {
        	Opportunity testOpp = [SELECT Id, Name, Amount, Number_of_Contact_Roles__c FROM Opportunity WHERE Id = :opp.Id];
            testOpp.Override_Contact_Req__c = false;
            testOpp.StageName = '5- Closed';
            System.debug(testOpp);
        	update testOpp;
        } catch (Exception e) {
            System.debug('I\'m in the ERROR message!');
            System.assert(e.getMessage().contains('contact roles'));
        }
        
        pb[0].isActive = false;
    }
}



Best Answer chosen by Brian Ford
logontokartiklogontokartik
Ok few things. 

FIrst in trigger on line 8 (opp.Override_Contact_Req__c = FALSE) thats doesnt seem right. Please change it to (!opp.Override_Contact_Req__c)

In your test class line 92, when you are doing SOQL you are not getting the StageName field and Override_Contact_Req__c field. Please change it to 
Opportunity testOpp = [SELECT Id, Name, Amount, StageName, Override_Contact_Req__c, Number_of_Contact_Roles__c FROM Opportunity WHERE Id = :opp.Id];

Try running test class again and see if it works.





All Answers

logontokartiklogontokartik
Is your test running successfully? Also is there a reaon why you have seeAllData=true? Maybe its failing even before its reaching your try catch block, (during the inserts you are doing)

Thank you.
Brian FordBrian Ford
The test does run successfully. I tried running it originally without seeAllData and I got the same result. I know it's reaching the try catch block because the System.debug statement on line 95 is running. 

The trigger should cause the update on line 96 to return an error because the test opp only has 2 contacts.
logontokartiklogontokartik
Ok few things. 

FIrst in trigger on line 8 (opp.Override_Contact_Req__c = FALSE) thats doesnt seem right. Please change it to (!opp.Override_Contact_Req__c)

In your test class line 92, when you are doing SOQL you are not getting the StageName field and Override_Contact_Req__c field. Please change it to 
Opportunity testOpp = [SELECT Id, Name, Amount, StageName, Override_Contact_Req__c, Number_of_Contact_Roles__c FROM Opportunity WHERE Id = :opp.Id];

Try running test class again and see if it works.





This was selected as the best answer
logontokartiklogontokartik
Also when you are inserting the opportunity in your test class on line 64, your trigger will throw Null Pointer Exception, it will not have trigger.oldMap.get(opp.id) at that time.
Brian FordBrian Ford
Thanks for your help. Still trying to wrap my head around how this all works. The SOQL query on line 92 was the problem.