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
Swaroopa Akula 10Swaroopa Akula 10 

test class covering only 56% code coverage

Apex class:/*




public class OpportunityTriggerHandlerverifiedIO {
    private static Boolean isExecuting = false;

    public static void handleClosedWonOpportunities(List<Opportunity> newOpportunities, Map<Id, Opportunity> oldOpportunityMap) {
        if (isExecuting) {
            // Skip trigger logic to avoid recursion
            return;
        }

        isExecuting = true;

        Set<Id> oppIds = new Set<Id>();
        Map<Id, APXT_Redlining__Contract_Agreement__c> oppToContractAgreementMap = new Map<Id, APXT_Redlining__Contract_Agreement__c>();
        
        for (Opportunity opp : newOpportunities) {
            // Check if the Opportunity is transitioning to 'Closed Won' and not a new Opportunity
            if (opp.StageName == 'Closed Won' && oldOpportunityMap.containsKey(opp.Id)) {
                oppIds.add(opp.Id);
            }
        }

        if (!oppIds.isEmpty()) {
            List<APXT_Redlining__Contract_Agreement__c> contractAgreements = [SELECT Id, Opportunity__c, APXT_Redlining__Status__c, Legal_review_completed__c,X3rd_Party_Paper__c, Customer_Signed_Date__c
                                                                            FROM APXT_Redlining__Contract_Agreement__c 
                                                                            WHERE CreatedDate > = 2023-08-13T15:13:08.000+0000 and Opportunity__c IN :oppIds];
            
           If(!contractAgreements.isEmpty()){
            
            for (APXT_Redlining__Contract_Agreement__c c : contractAgreements) {
                // Build the map of Opportunity Ids to Contract Agreement records
                oppToContractAgreementMap.put(c.Opportunity__c, c);
            }

            
            for (Opportunity opp : newOpportunities) {

                // Check if the Opportunity is transitioning to 'Closed Won' and has an existing Contract Agreement
                if (opp.StageName == 'Closed Won' && oppToContractAgreementMap.containsKey(opp.Id)) {
                    APXT_Redlining__Contract_Agreement__c contractAgreement = oppToContractAgreementMap.get(opp.Id);

                    
                    // Check if the contract agreement is active and not verified
                    if (contractAgreement.APXT_Redlining__Status__c == 'Active' && !contractAgreement.Legal_review_completed__c && contractAgreement.X3rd_Party_Paper__c == true )
                    //if (contractAgreement.APXT_Redlining__Status__c == 'Active' && !contractAgreement.Legal_review_completed__c && contractAgreement.X3rd_Party_Paper__c == true)||(contractAgreement)
                    {
                        opp.addError('Third party paper must be approved by Legal, please submit a "Legal Case".');
                    }
                    
                    else if((contractAgreement.APXT_Redlining__Status__c == 'Active'&& contractAgreement.Customer_Signed_Date__c==null)||(!(contractAgreement.APXT_Redlining__Status__c == 'Active')))
                    {
                        opp.addError('"To ‘Closed won’ the Opportunity, the Contract must be an active Contract Agreement and the customer must be signed".');
                    }

                
                }
                else if (opp.StageName == 'Closed Won' && !oppToContractAgreementMap.containsKey(opp.Id)) {
                    opp.addError('Closed Won Opportunity must have a contract agreement.');
                }

            }
        }
        }

        isExecuting = false;
    }
}

 

Trigger:

Trigger OpportunityTriggerHandlerverifiedIO on Opportunity (before update) {
    OpportunityTriggerHandlerverifiedIO.handleClosedWonOpportunities(Trigger.new, Trigger.oldMap);
}

 

 

Test class:
@isTest
private class OpportunityTriggerHandlerverifiedIOTest {
    @isTest
    static void testOpportunityTriggerHandler() {
        // Create test data
        Opportunity testOpportunity = new Opportunity(
            Name = 'Test Opportunity1',
            StageName = 'Sales Meeting Set',
            CloseDate = Date.today(),
            Start_Date__c=Date.today(),
            End_Date__c =Date.today(),
            Contact_Role_added__c = true,
            Billing_Term__c = 'Net 30',
            Type='New Logo',
            Billing_Account_Name__c='Test Account',
            Billing_Contact_Name__c='Test contact name',
            Billing_Email__c='test@gmail.com',
            Billing_Street__c='1234 test street',
            Billing_Postal_Code__c='75046',
            Billing_Country__c='US',
            Billing_City__c='Dallas',
            Deal_Term_In_Months__c='12',
            Is_timeframe_to_launch_within_30_days__c='Yes'
        );
        insert testOpportunity;

        APXT_Redlining__Contract_Agreement__c contract = new APXT_Redlining__Contract_Agreement__c(
            Opportunity__c = testOpportunity.Id,
            APXT_Redlining__Status__c = 'Active',
             Legal_review_completed__c = true,
            X3rd_Party_Paper__c = true,
            Customer_Signed_Date__c=Date.today()
        );
        insert contract;

     // Update the Opportunity to trigger the trigger
        testOpportunity.StageName = 'Closed Lost';
        testOpportunity.Reason_Lost__c = 'Went with Competitor – Price';
        try {
            Test.startTest();
            update testOpportunity;
            Test.stopTest();
            // If no exception is thrown, the test should fail
            //System.assert(false, 'Expected DMLException but no exception was thrown.');
        } catch (DmlException e) {
            // Assert the error message for Closed Lost Opportunity
            
            
             Boolean expectedExceptionThrown =  e.getMessage().contains('Closed Won Opportunity must have a contract agreement') ? true : false;
           System.AssertEquals(expectedExceptionThrown, true);          
            //System.assertEquals('Closed Won Opportunity must have a contract agreement.', e.getMessage());
        }
        

        // Update the Opportunity again to meet the conditions
        testOpportunity.StageName = 'Closed Won';
        try {
          //  Test.startTest();
            update testOpportunity;
           // Test.stopTest();
            // If no exception is thrown, the test should fail
            //System.assert(false, 'Expected DMLException but no exception was thrown.');
        }catch (DmlException e) {
    System.debug('Caught Exception Message: ' + e.getMessage());
    System.assertEquals('Third party paper must be approved by Legal, please submit a "Legal Case".', e.getMessage());
}

        
        
         

        // Update the Contract Agreement to meet the conditions
        contract.Verified_Signed_IO__c = true;
        update contract;

        // Update the Opportunity again to satisfy the conditions
        testOpportunity.StageName = 'Closed Won';
        try {
            //Test.startTest();
            update testOpportunity;
           // Test.stopTest();
            // If an exception is thrown, the test should fail
            System.assert(true, 'No exception should be thrown.');
        } catch (DmlException e) {
            // If an exception is thrown, the test should fail
            System.assert(false, 'No exception should be thrown.');
        }
    }
}


Above test class is covering only 53%. I have updated the lines in bold which are not covered. Can anyone help me fix this code coverage issue

HarshHarsh (Salesforce Developers) 
Hi Swaroopa,
You have to follow the following best practice to write effective test cases, you need to ensure to include the below points in the test class.
  • Test class must start with @isTest annotation.
  •  To deploy to production at least 75% code coverage is required.
  • We should ensure that every use case includes positive, negative, bulk, and single record.
  • One Assert Statement per method: Always put assert statements for negative and positive tests.
    • System.assert(condition, msg)
    • System.assertEquals(expected, actual, msg)
    • System.assertNotEquals(expected, actual, msg)
  • @testSetup to create test records once in a method and use them in every test method in the test class.
  • Create TestFactory class with @isTest annotation to exclude from organization code size limit.
  • No SeeAllData=true: Always use ( seeAllData = false ) at the class or method level. User, profile, organization, AsyncApexjob, Corntrigger, RecordType, ApexClass, ApexComponent, ApexPage we can access without (seeAllData=true).
  • As Apex runs in system mode so permission and record sharing are not taken into account. So we need to use System.runAs to enforce record sharing.
  • Avoid Using Hard Coding Ids anywhere in the test Class or any apex class
  • Governor limits: Using Test.startTest()gives developers a new set of governor limits for the act stage of their test. Test.stopTest() then allows them to return to their previous governor limits. Test classes must test for Governor Limits using Limits Class
  • Testing Exception: Any exceptions that are caught in the production methods should be tested by feeding the test data that throws an exception. Exception Type and the error message should be asserted
  • Exercise bulk trigger functionality – use at least 200 records in your tests


For Code Coverage Best Practices visit the following link 
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_code_coverage_best_pract.htm

Please mark it as Best Answer if the above information was helpful.

Thanks.