+ Start a Discussion
Adam FranklinAdam Franklin 

Milestone Calculator - System.NullPointerException: Attempt to de-reference a null object

Hi,

I'm working on a calculator to dynamically determine milestone times based on various attributes of cases.  I have it working in the sandbox, and 95% code coverage, but I am having trouble generating a test to hit that last line of code.  Instead, my testmethod fails and I get the error message referenced above.

Right now, I have three milestones: First Response, Update Customer, and Solution delivered.  Each calculates dynamically based on the milestone and severity level.   

Here is my calculator:
global class myMilestoneTimeCalculator implements Support.MilestoneTriggerTimeCalculator {   
     global Integer calculateMilestoneTriggerTime(String caseId, String milestoneTypeId){
        Case c = [SELECT RecordType.Name, Severity_level__c, Priority FROM Case WHERE Id=:caseId];
        String rt = c.RecordType.Name;
        String sev = c.Severity_Level__c;
        String pLev = c.Priority;
        
         //this is only necessary for now, to prevent any stepping on toes, also we don't want to calc w/o a sev level
         If(rt.equals('Product Support') && c.Severity_Level__c != null){
             //start by checking milestone
           MilestoneType mt = [SELECT Name FROM MilestoneType WHERE Id=:milestoneTypeId];
             if (mt.Name != null && mt.Name.equals('First response from agent')) {
            //now sev levels 
                 if(sev != null && sev.equals('Severity 2')){return 240;}
                 else if(sev !=null && sev.equals('Severity 3')){return 480;}
                 else {return 960;}
                 
             }
             else if(mt.Name !=null && mt.Name.equals('Update Customer')){ 
                 //we're in the holding phase, providing customer updates
                 if(sev != null && sev.equals('Severity 2')){return 180;}
                 else if(sev !=null && sev.equals('Severity 3')){return 480;}
                 else {return 960;}
             }
             //our SLA requires a solution or action plan within certain timeframes.  we can do that here.
             else if(mt.Name != null && mt.Name.equals('Solution or Action Plan Delivered')){
                 if(sev != null && sev.equals('Severity 2')){return 960;}
                 else if(sev !=null && sev.equals('Severity 3')){return 1440;}
                 else {return 2400;}
             }
             else {return 960;}         
         }
         else {return 960;}
     }
}

I wrote a few helper methods, which I've tested and can confirm work.  Here is the one for getting the milestone :
public static MilestoneType msType(String MilestoneName){
        List<MilestoneType> mtLst = [SELECT Id, Name FROM MilestoneType Where Name =:MilestoneName LIMIT 1];
        if(mtLst.isEmpty() || mtLst.size() > 1) {return null;}
        else{
        MilestoneType mt = mtLst[0];
        return mt;  
        }
     }

And here is a testmethod that fails :
@isTest static void nullMilestone(){
        Case c = msTestDataFactory.cGen('Product Support','Severity 4','Low');
        myMilestoneTimeCalculator calculator = new myMilestoneTimeCalculator();
        MilestoneType mt = msTestDataFactory.msType('');
        Integer actualTriggerTime = calculator.calculateMilestoneTriggerTime(c.Id, mt.Id);
        System.debug('no milestone : '+actualTriggerTime);
        System.assertEquals(960, actualTriggerTime);
        }

So basically, I'm trying to test for an unlikely case (probably an impossible case) of a Case with no milestones invoking the milestone calculator.   I'm not sure how to do this without getting the error above.  

I'd appreciate any suggestions or general feedback on my actual code - I started with a snippet from the Salesforce resources, but it has obviously grown into it's own thing.
Best Answer chosen by Adam Franklin
santoshgoresantoshgore
Hi Adam,

You can avoid error in test class by checking null conddition as follow:
@isTest 
static void nullMilestone(){
        Case c = msTestDataFactory.cGen('Product Support','Severity 4','Low');
        myMilestoneTimeCalculator calculator = new myMilestoneTimeCalculator();
        MilestoneType mt = msTestDataFactory.msType('');
       
       if(c != null && mt != null) {
               Integer actualTriggerTime = calculator.calculateMilestoneTriggerTime(c.Id, mt.Id);
               System.debug('no milestone : '+actualTriggerTime);
               System.assertEquals(960, actualTriggerTime);
       }
}

Another way is you need to make sure that case should have milestone data exist.

Thanks,
Santosh
 

All Answers

santoshgoresantoshgore
Hi Adam,

You have not specified complete stacktrace of errors it is quite difficult to point out the error.

Below is the probable cause of the error:
      In test class,line no. 4, 
        MilestoneType mt = msTestDataFactory.msType('');
        your helper method will return null because of the no record found or more thean 1 record found
so variable "mt" will be null.If you use mt.id in next line(line no. 5 in test class),this will become null.id which is the reason of error.

Thanks,
Santosh
Adam FranklinAdam Franklin
Thanks, Santosh, for your reply.   

Here's the stacktrace: Class.myMilestoneTimeCalculatorTest.nullMilestone: line 149, column 1.  That refers to the line:
Integer actualTriggerTime = calculator.calculateMilestoneTriggerTime(c.Id, mt.Id);

I think that you're correct that the helper method returns null becuase there is no match to a null milestone name.   What I'm not sure of is how I should either write the test class, or refactor my code so that it is more resilient or logical.

The only line unaccounted for in my Calculator is line 31, which is the result for when a case matches on Record Type and Severity, but does not have a milestone.  I'm not actually sure how the calculator would be invoked in this case, but if it can happen, I'd prefer to make sure it's tested.
santoshgoresantoshgore
Hi Adam,

You can avoid error in test class by checking null conddition as follow:
@isTest 
static void nullMilestone(){
        Case c = msTestDataFactory.cGen('Product Support','Severity 4','Low');
        myMilestoneTimeCalculator calculator = new myMilestoneTimeCalculator();
        MilestoneType mt = msTestDataFactory.msType('');
       
       if(c != null && mt != null) {
               Integer actualTriggerTime = calculator.calculateMilestoneTriggerTime(c.Id, mt.Id);
               System.debug('no milestone : '+actualTriggerTime);
               System.assertEquals(960, actualTriggerTime);
       }
}

Another way is you need to make sure that case should have milestone data exist.

Thanks,
Santosh
 
This was selected as the best answer
Adam FranklinAdam Franklin
Thanks, Santosh!