+ Start a Discussion
Bablu Kumar PanditBablu Kumar Pandit 

How to write test class for Below i write but not code covarge

//-----Handler Class------//
public class OppPrintCampaign{
    public static void InsertOpp(List<Opportunity> lstopp,Map<Id,Opportunity> mapIdToSatge){
        Set<Id> setOfAccId = New Set<Id>();
        List<Account> lstupdateacc = New List<Account>();
        List<Opportunity> lstofClosedLostOpp = New List<Opportunity>();
        Campaign objcamp = [Select Id,name from campaign where Id = '7012v000002KBp9'];
        for(Opportunity objopp:lstopp){
            if(objopp.accountId != null && objopp.stageName == 'Closed Lost' && objopp.StageName != mapIdToSatge.get(objopp.Id).stageName){
                setOfAccId.add(objopp.accountId);
            }
		}
        System.debug('-----setOfAccId-----'+setOfAccId);
         for(Opportunity objopp :[Select Id,Name ,Stagename ,AccountId from Opportunity where AccountId IN:setOfAccId]){        
             if(objopp.StageName != 'Closed Lost'){
                 lstofClosedLostOpp.add(objopp);
                 break;
             }
        }
        System.debug('----lstofClosedLostOpp----'+lstofClosedLostOpp.size());
        if(lstofClosedLostOpp.size() == 0){
          	 for(Account objacc:[Select Id,Name from Account where Id IN:setOfAccId]){
             	objacc.Assign_Engments__c = objcamp.name;
             	lstupdateacc.add(objacc);
             } 
        }
        
        System.debug('-----lstupdateacc-----'+lstupdateacc);
        update lstupdateacc;
	}
}

//------Test Class-----//
@isTest
public class OppPrintCampaignTest {
    static testmethod void method1(){
        
        Account objacc = new Account();
        objacc.name = 'Test';
        objacc.Rating = 'Cold';
        insert objacc;
        
        Opportunity objopp = New Opportunity();
        objopp.name = 'Test opp';
        objopp.CloseDate = System.today();
        objopp.AccountId = objacc.Id;
        objopp.StageName = 'Closed Lost';
        insert objopp;       
    }
}

 
Andrew GAndrew G
Hi

You indicate that OppPrintCampaign is part of a Handler class.  How is it invoked?

Looking at the format of the method
public static void InsertOpp(List<Opportunity> lstopp,Map<Id,Opportunity> mapIdToSatge){
I am assuming that lstopp is trigger new and mapIdToSatge is trigger oldMap.

Based on that assumption, you will need to fire an update on your opportunity in the test class as the insert alone will not fire the handler method.
Also your code is checking for a change from Open to Closed Lost, so insert with a different stage.
//------Test Class-----//
@isTest
public class OppPrintCampaignTest {
    static testmethod void method1(){
        
        Account objacc = new Account();
        objacc.name = 'Test';
        objacc.Rating = 'Cold';
        insert objacc;
        
        Opportunity objopp = New Opportunity();
        objopp.name = 'Test opp';
        objopp.CloseDate = System.today();
        objopp.AccountId = objacc.Id;
        objopp.StageName = 'New';
        insert objopp;       
        
        //force an update so the code runs
        objopp.StageName = 'Closed Lost'; 
        update objopp; 

    }
}

Regards
Andrew

p.s. all code provided uncompiled and as-is
 
Bablu Kumar PanditBablu Kumar Pandit
Hey Andrew,

your assumption is correct trigger fire on Opportunity in which lstopp whcih has New List of trigger and oldmap is old value of trigger

i am tried above code but not cover covrage is 29% 
Please guide how to increacse covrage
Andrew GAndrew G
Reading the code and the test class, it should work.

i have simulated that code in a dev environment and I can achieve 86% coverage.

I suspect the issue is with the Campaign not being returned in you code.  The campaign will exist as a record in the live environment, and therefore is not visible to the test class.
So, I would adjust as follows: (note that I don't think Ids should ever be hardcoded into apex class, it makes them less portable.)
Class:
/** 
* Created by andrewg on 31/07/2020. 
*/ 
public with sharing class OppPrintCampaign {
    public static void InsertOpp(List<Opportunity> lstopp,Map<Id,Opportunity> mapIdToSatge){
        Set<Id> setOfAccId = new Set<Id>();
        List<Account> lstupdateacc = new List<Account>();
//        List<Opportunity> lstofClosedLostOpp = new List<Opportunity>();
//        Campaign objcamp = [Select Id,name from campaign where Id = '7012v000002KBp9'];
        Campaign objcamp = [SELECT Id,Name FROM Campaign WHERE Name = 'Some test'];

        for(Opportunity objopp:lstopp){
            if(objopp.AccountId != null && objopp.StageName == 'Closed Lost' && objopp.StageName != mapIdToSatge.get(objopp.Id).StageName){
                setOfAccId.add(objopp.AccountId);
            }
        }
        //next element does what exactly?  
//makes another query to confirm my first code was correct? removed to improve coverage
        /*
        System.debug('-----setOfAccId-----'+setOfAccId);
        for(Opportunity objopp :[SELECT Id,Name ,StageName ,AccountId FROM Opportunity WHERE AccountId IN:setOfAccId]){
            if(objopp.StageName != 'Closed Lost'){
                lstofClosedLostOpp.add(objopp);
                break;
            }
        }*/
        if(setOfAccId.size() > 0){
            for(Account objacc:[SELECT Id,Name FROM Account WHERE Id IN:setOfAccId]){
                objacc.Site = objcamp.Name;
                lstupdateacc.add(objacc);
            }
        }

        System.debug('-----lstupdateacc-----'+lstupdateacc);
        update lstupdateacc;
    }
}
Test class
Since we appear worried about checking if the value was updated correctly, lets also do a negative test where the record is not updated.
 
/**
 * Created by andrewg on 31/07/2020.
 */

@IsTest
private class oppPrintCampaignTest {
    @TestSetup
    static void setupData(){
        Account objacc = new Account();
        objacc.Name = 'Test';
        objacc.Rating = 'Cold';
        insert objacc;

        Opportunity objopp = new Opportunity();
        objopp.Name = 'Test opp';
        objopp.CloseDate = System.today();
        objopp.AccountId = objacc.Id;
        objopp.StageName = 'New';
        insert objopp;

        Campaign camp = new Campaign(
                Name = 'Some test',
                IsActive = true
        );
        insert camp;
    }

    @IsTest
    static void testFieldUpdate(){
        Opportunity objopp = [SELECT Id, Name, StageName FROM Opportunity WHERE Name = 'Test opp'];

        //force an update so the code runs
        objopp.StageName = 'Closed Lost';
        update objopp;

        Account updatedAccount = [SELECT Id, Site FROM Account WHERE Name = 'Test'];
        System.assertEquals('Some test',updatedAccount.Site);
    }

    @IsTest
    static void testFieldNonUpdate(){
        Opportunity objopp = [SELECT Id, Name, StageName FROM Opportunity WHERE Name = 'Test opp'];

        //force an update so the code runs
        objopp.StageName = 'Closed Won';
        update objopp;

        Account updatedAccount = [SELECT Id, Site FROM Account WHERE Name = 'Test'];
        System.assertEquals(null,updatedAccount.Site);

    }

}
Note, we also use the @TestSetup convention to setup the test data once.
We have also removed the use of testMethod as that has been deprecated. 
ref: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_isTest.htm

The above will give 100% coverage and if your Trigger structure looks like below, it would 100% coverage also:
/**
 * Created by andrewg on 31/07/2020.
 */

trigger oppTrigger on Opportunity (after update) {
    System.debug('DEBUG - In Trigger - oppTrigger');

    if ( Trigger.isAfter && Trigger.isUpdate ) {
        System.debug('In Trigger - about to call on after update');
        OppPrintCampaign.InsertOpp(Trigger.New, Trigger.OldMap);
    }


}

Note also, i would change the method name, as insertOpp is not really a clear name for what the method is doing.
For a naming convention, my handler would be named opportunityTriggerHandler - some may say not very original, but it means I can add other logic (methods) to the class but the class purpose is still quite obvious.
I would then change the method name to something like setAccountCampaignReference - yes, a little unwieldy, but it is quite obvious what the method is about to do.

That way I could read the in the trigger as:
if ( Trigger.isAfter && Trigger.isUpdate ) {
        System.debug('In Trigger - about to call on after update');
        opportunityTriggerHandler.setAccountCampaignReference (Trigger.New, Trigger.OldMap);
}
And i would have a clear idea of what was happening without necessarily going to the handler class to find out.


Regards
Andrew