0

I need to write a unit test for a class that I have created. Mostly based on Opportunities and OpportunityLineItem.

For some reason, I cannot get coverage past my for loop. I have tried everything, but I simply do not understand why I cannot seem to get coverage past my for loop.

For reference, my for loop is the last bit of code that is highlighted in blue. Everything else past my for loop is in red. Does this mean that I am not getting past my for loop? Have I correctly created OpportunityLineItem in my test class?

I need some help in understanding how to fix my current test class. I am very new to unit testing, so I am really looking to understand more than anything. Any help is appreciated. thank you.

This is a portion of my current class:

    Public class TriggerHandler{
        
        //public lists to hold lists based on cancellation status and opportunity line items
        Public static List<OpportunityLineItem> lstOppProd = new List<OpportunityLineItem>();
        Public static List<Contact> lstContactsToProcess = new List<Contact>();
        
        public static void processOpps(List<Opportunity> newOpp){
         
            //map helper of Opportunities based on cancelled status
            Map<Id, Opportunity> mapCancelledSubs = New Map<Id, Opportunity>([SELECT id From Opportunity Where Opportunity.Id in :newOpp 
                                                                             AND Order_Status__c IN ('Cancelled','Expired','Pending Cancellation')
                                                                             And Type ='Subscription' And (Not Coupon_Codes__c Like '%test%')]);
            
            //list of OpportunityLineItems tied to newOpp
            list<OpportunityLineItem> lstOppProd = [Select id, OpportunityId, ContactId__c, ProductCode From OpportunityLineItem
                                                    Where OpportunityId In (Select Opportunity.Id From Opportunity Where Id In :newOpp AND
                                                                            Type = 'Subscription'And AccountId != Null)
                                                                            And OrderItemType__c = 'Line Item'];
    
            
            for(OpportunityLineItem oppProd : lstOppProd){
                
                List<Object> paramSurveyUrl = new List<Object>{oppProd.ContactId__c,oppProd.OpportunityId, oppProd.ProductCode, myDate};
                List<Object> paramProdFieldAbbv = new List<Object>{productAbbreviations.get(oppProd.ProductCode)};

This is my test class:

@isTest
public class TestTriggerHandler {
    
    //testing trigger by passing lists, and creating Test Opportunities and Accounts
    static testmethod void afterUpdateTestMethod1(){
        
        List<OpportunityLineItem> lstOppProd = new List<OpportunityLineItem>();
        List<Contact> lstContactsToProcess = new List<Contact>();
        
        //create Test Opportunity
        Opportunity opp1 = new Opportunity(Name='test opp', StageName='stage', Probability = 95, CloseDate=system.today(), Order_Status__c = 'Pending');
        
        insert opp1;
        opp1.Amount = 1000;
        opp1.StageName = 'Closed Won';
        update opp1;

        ///create Account
        Id accRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Person Account').getRecordTypeId();
        Account Accnt = new Account(RecordTypeID = accRecordTypeId,FirstName = 'Test FName 1',LastName = 'Test LName 1',PersonEmail ='[email protected]',
                                    PersonMailingStreet = 'Test Street 01',PersonMailingPostalCode = '12345',PersonMailingCity = 'City',PersonHomePhone = '3456789876',PersonMobilePhone = '1234567897',
                                   Contact_Stage__pc = '75 - Raving Fan', Type ='Customer');
        try{insert Accnt;}
        catch(Exception e){system.debug(e.getMessage() + e.getLineNumber() + e.getTypeName());}
        
        //creating opportunity line item, and product
        Id pricebookId = Test.getStandardPricebookId();
        
        Product2 prd1 = new Product2 (Name='Test Product',Description='Test Product Entry 1', productCode = '302541', isActive = true);
        insert prd1;
        
        PricebookEntry pbe1 = new PricebookEntry (Product2ID = prd1.id, Pricebook2ID = pricebookId, UnitPrice = 247, isActive = true);
        insert pbe1;
       
        //create Test Opportunity
        Opportunity opp = new Opportunity(Name='test opp', AccountId = Accnt.Id, StageName='Closed-Won', CloseDate=system.today(), Order_Status__c = 'Cancelled', Type = 'Subscription');
        
        update opp;
             
        OpportunityLineItem lineItem1 = new OpportunityLineItem (OpportunityID = opp.id, ContactId__c = Accnt.PersonContactId, Quantity=1, TotalPrice = 247, OrderItemType__c = 'Line Item');
        
        insert lineItem1;
        
        opp.Order_Status__c = 'Active';
         
        try{update opp;}
        catch(Exception e){system.debug(e.getMessage() + e.getLineNumber() + e.getTypeName());}

    }
4
  • 1
    At the very least, you'll want to get rid of the try/catch that surrounds your insert Acct; and update opp;. Getting exceptions in a test method is very much something that you want to know about, and printing the exception to the debug log and swallowing the exception just makes it harder to have any issues brought to your attention.
    – Derek F
    Nov 1, 2021 at 19:56
  • You're never inserting opp. You're inserting opp1 for some reason and then making a new one. Then when you do the OLI the opp.Id is null so that doesn't get created either. So when it's time to do the for loop of your OLIs there is none and thus it's not covered. I'm rewriting your test stay tuned. Nov 1, 2021 at 20:25
  • @DanWooding thank you so much, for your explanation and help. I have been going crazy trying to figure this out, especially since I am so new to unit testing.
    – Y_m5437
    Nov 1, 2021 at 20:36
  • @derekF that makes sense, thank you!
    – Y_m5437
    Nov 1, 2021 at 20:37

2 Answers 2

2

The general rule in unit testing is that you are 100% responsible for setting up test data. You need to ensure that the code you're trying to test has everything that it needs in order to run. "Everything" here extends to more than just inserting records, the data on those records needs to be appropriate too.

In the developer console, when you look at the code coverage, every line that is:

  • blue has been "covered" (that is, there was a unit test that caused that line to be executed, and I believe the test needs to pass as well, failed tests don't contribute to coverage).
  • red is "uncovered" (they were not executed as part of a test).
  • If a line doesn't have any color, then Salesforce determined that it's not something that needs to be covered (things like empty lines, comments, lines with only curly braces).

So when you see your for() being blue, but everything inside of it being red, that means that there was nothing for your loop to iterate over.

Test Debugging

Now that we know that you aren't getting into the for() loop, you need to start working backwards to understand why.

  • lstOppProd is empty
  • The query for lstOppProd only returns records that are related to an Opportunity where
    • The Opp has an Id of an opp in newOpp
    • The Opp Type is 'subscription'
    • The Opp has an AccountId
    • The Opp Line Item has OrderItemType__c = 'Line Item'

The structure of your queries strikes me as odd, but let's move on. Now let's look back at your test method to see if you're inserting any data that satisfies those requirements.

Opportunity opp = new Opportunity(Name='test opp', AccountId = Accnt.Id, StageName='Closed-Won', CloseDate=system.today(), Order_Status__c = 'Cancelled', Type = 'Subscription');

update opp;

You are creating an Opportunity with an AccountId and Type = 'subscription', and I have to assume that performing DML on it causes your handler to run. You haven't set an Id on this opportunity, so the update opp; line should fail (no id sdpecified in update operation, or something like that).

That's what I expect the immediate issue to be. Your test is failing because you're trying to update an Opportunity with no Id. Perhaps you meant to add Id = opp1.Id into the Opportunity opp = new Opportunity(...); line.

Let's continue

After you address that issue, it appears that an appropriate Opportunity is being created.

Now, are you creating an appropriate OLI (Opportunity Line Item) for the code you're testing?

  • You're setting the OpportunityId to that of your opp
  • You're setting OrderItemType__c to 'Line Item'

So it does appear that you are creating appropriate data, it's just a matter of getting your test to execute that far without running into an error.

1
  • Thank you so much, This is incredibly helpful. I appreciate the fact that you took the time to explain everything to me and how you broke it down piece by piece. I will look back at my unit test and make the appropriate changes.
    – Y_m5437
    Nov 1, 2021 at 20:41
1

I'd move things into @testSetup and then your test method just needs to call what you are doing. This will help narrow down issues because you'll know the records will create and then you're only working with what you need in the test method. If you start to separate your class queries into their own methods then you just need to pass over a Opportunity list instead of relying on DML to trigger what you need. Something like this:

public with sharing class TestTriggerHandler
{

@TestSetup
static void makeData()
{
    Id accRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Person Account').getRecordTypeId();
    Id pricebookId = Test.getStandardPricebookId();

    Account accnt = new Account(
        RecordTypeID = accRecordTypeId,
        FirstName = 'Test FName 1',
        LastName = 'Test LName 1',
        PersonEmail ='[email protected]',
        PersonMailingStreet = 'Test Street 01',
        PersonMailingPostalCode = '12345',
        PersonMailingCity = 'City',
        PersonHomePhone = '3456789876',
        PersonMobilePhone = '1234567897',
        Contact_Stage__pc = '75 - Raving Fan',
        Type ='Customer');
    insert accnt;
        
    Product2 prd1 = new Product2(
        Name = 'Test Product',
        Description = 'Test Product Entry 1', 
        productCode = '302541', 
        isActive = true);
    insert prd1;
    
    PricebookEntry pbe1 = new PricebookEntry(
        Product2ID = prd1.Id,
        Pricebook2ID = pricebookId,
        UnitPrice = 247, 
        isActive = true);
    insert pbe1;

    Opportunity opp = new Opportunity(
        Name ='test opp', 
        AccountId = accnt.Id, 
        StageName = 'Closed-Won', 
        CloseDate = System.today(),
        Order_Status__c = 'Cancelled', 
        Type = 'Subscription');
    insert opp;
             
    OpportunityLineItem lineItem1 = new OpportunityLineItem(
        OpportunityID = opp.Id, 
        ContactId__c = accnt.PersonContactId,
        Quantity = 1, 
        TotalPrice = 247, 
        OrderItemType__c = 'Line Item');
    insert lineItem1;
    
}

@IsTest
static void methodName()
{
    List<Opportunity> oppyList = [SELECT Id FROM Opportunity];
    
    Test.startTest();
        TriggerHandler.processOpps(oppyList);
    Test.stopTest();       
    
    System.assertEquals(); 
}

}

Finally, don't use capitals for variables. It'll get confusing later on.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .