Monday, July 01, 2019

Tips and Tricks : Test class for Invocable method


Issue :

I got 100% coverage in my sandbox but when run validation for deployment it returns 0% coverage

It turn out that in my sandbox, I am depending on Process Builder to Invocable Apex class, as long I manipulate test data that fire Process Builder it will call Invocable class. This is not useful when deploying it to Production although it gets deployed together with Process Builder.

The correct way is to direct call Invocable method inside test class itself.

Example of class :


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
global class MyCustomObject_StatusUpdate_Util{
 @InvocableMethod(label='Update Quote Status')
  public static void updateQuote(Request[] requests) {
        Set<Id> setOppId = new Set<Id>();
        List<SBQQ__Quote__c> listQuoteToUpdate = new List<SBQQ__Quote__c>();

        for(Request request : requests) {
           setOppId.add(request.recordId);
        }
       
        if(setOppId.size()>0){
            List<SBQQ__Quote__c> listQuote =[Select Id,BypassValidationRule__c,SBQQ__Status__c from SBQQ__Quote__c where SBQQ__Opportunity2__c IN :setOppId  ];

             for(SBQQ__Quote__c quote : listQuote)  {
                 quote.BypassValidationRule__c = quote.BypassValidationRule__c?false:true;
                 quote.SBQQ__Status__c =requests[0].quoteStatus;
                 listQuoteToUpdate.add(quote);
             } 
            if(listQuoteToUpdate.size()>0){
                 Database.SaveResult [] updateResult = Database.update(listQuoteToUpdate, false);
            }
         }
     }

 global class Request{
        @InvocableVariable(label='Opportunity ID' required=true)
        public Id recordId;

        @InvocableVariable(label='Quote Status' required=true)
        public String quoteStatus;
      
    }
}

Example of test class :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static testMethod void testCallInvocableClass() {
        
     Test.startTest();
     My_Custom_Object__c myObject =[Select Id,Approval_Status__c FROM My_Custom_Object__c WHere Opportunity__c =:quote.SBQQ__Opportunity2__c];

    myObject.Approval_Status__c ='Approved';
    //this will work only in sandbox, not in deployment.Logically this will fire process builder
    update myObject;

 //to makesure test class is cover, need to call invocable class directly, which in this scenario I need to instantiate
 // inner class 
    List<MyCustomObject_StatusUpdate_Util.Request> listRequest =new List<MyCustomObject_StatusUpdate_Util.Request>();
    MyCustomObject_StatusUpdate_Util.Request req = new MyCustomObject_StatusUpdate_Util.Request();
    req.recordId=quote.SBQQ__Opportunity2__c;
    req.quoteStatus='In Progress';
    listRequest.add(req);
    
    //the call the method directly - here my method is updateQuote
    MyCustomObject_StatusUpdate_Util.updateQuote(listRequest);
   
    listQuote =[select id,SBQQ__Status__c  from SBQQ__Quote__c where SBQQ__Opportunity2__c=:listOpp[0].Id ];
    system.assertEquals('In Progress', listQuote[0].SBQQ__Status__c)
  
    Test.stopTest();
  
  }

No comments:

Post a Comment