0

I have created a trigger which calls a future class to make http callout to a third party url, everthing is working fine here but the test class is not covering the opportunity fields IsWon & IsClosed. What modification do I need in test class to make the code coverage at least 75 % for this trigger.

// Apex trigger

trigger oppTrigger on Opportunity (before update) {

String oppType = '';
for(Opportunity opp : Trigger.new){

if (opp.IsClosed == true){  // closed
  if (opp.IsWon == true){
    oppType = 'Won'; // closed-won
   }else{
    oppType = 'Lost'; // closed-lost
   }
} else { // open
       oppType = 'Open'; 
    }
  // call a method with @future annotation
   futureCls.srvcCallout(opp.id,opp.Amount,oppType); 
 }
}

// future class for trigger with future method

global class futureCls {
@future(callout=true)
Public static void srvcCallout(String oppId, Decimal oppAmt, String oppType){

     // Create http request
     HttpRequest req = new HttpRequest();
     req.setMethod('POST');
     req.setHeader('Content-Type', 'application/json;charset=UTF-8');     
     req.setEndpoint('https://www.testurl.com/salesforce/opp-change'+'?id='+oppId+'&amt='+oppAmt+'&stage='+oppType);

     // create web service
     Http http = new Http();
      try {
        // Execute web service call here     
        HTTPResponse res = http.send(req);  
        // Debug messages
        System.debug('RESPONSE:'+res.toString());
        System.debug('STATUS:'+res.getStatus());
        System.debug('STATUS_CODE:'+res.getStatusCode());
        System.debug('BODY:'+res.getBody());

        } catch(System.CalloutException e) {
             // Exception handler
             System.debug('Error connecting to Paperless..');
       }   
     }
 }

// Test class for the trigger where I'm stuck:-

@isTest
private class futureCls_Test {  

private static testMethod void paperlessCallout_Test() {        

    // Test for trigger on opportunity update
    Opportunity opp = new Opportunity(Name='test opp',StageName='stage', Probability = 95, CloseDate=system.today());
    insert opp;

    // Test for different opportunity stages
    opp.Amount = 1000;
    opp.StageName = 'Closed Won';
    update opp;

    opp.StageName = 'Closed Lost';
    update opp;

    opp.StageName = 'Open';
    update opp;

    // cover http callout      
    Test.startTest();
    Test.setMock(HttpCalloutMock.class, new futureClsCalloutMock()); 
    Test.stopTest();

    // Verify http request & response
    Http h = new Http();        
    HttpRequest req1 = new HttpRequest();
    req1.setEndpoint('https://mywebsrvc.com/foo/bar'); 
    req1.setMethod('POST');
    req1.setHeader('Content-Type', 'application/json');

    // Verify response
    HttpResponse res1 = h.send(req1);
    System.assertEquals('{"foo":"bar"}', res1.getBody());

   }
  }
  • 4
    Remember that if you don't put any System.assert() Statements into your test class you're actually testing nothing. Add some Asserts to check everything you've done gives you the expected result. – Alexander Aeons Torn Jul 25 '17 at 12:25
  • 1
    Indeed. Verifying that your code works as you expect it to work is the most important part of unit testing. It’s also one of the things that Force.com developers commonly neglect. Unit tests that do not verify the results of the code aren’t true unit tests. They are commonly referred to as smoke tests, which aren’t nearly as effective or informative as true unit tests. - How to Write Good Unit Tests – Adrian Larson Jul 25 '17 at 13:48
  • @AlexanderAeonsTorn as I'm newbie to salesforce, can you give me an example on how to use System.assert() here in my test class. – kapil Jul 25 '17 at 13:57
  • 1
    Adrian provided you links with useful information on the topic. ;) I would add this one : salesforce.stackexchange.com/questions/55386/… This would be enough to cover the basics of how to write efficient test. And this will practices will improve the safety of your code, specially when you start making version of it or adding additional code to your org. – Alexander Aeons Torn Jul 25 '17 at 14:08
  • @AlexanderAeonsTorn have updated my question with System.assert() statements, but not sure that am I doing it correctly or not. though I'm getting 94% coverage now. – kapil Jul 26 '17 at 14:52
2

The value of the picklist StageName is incorrect in your test class. It should be Closed Won instead of Closed/Won

Updated test class:

@isTest
private class futureCls_Test {  

 private static testMethod void srvcCallout_Test() {        

    Test.startTest();

    // Unit test to cover trigger update event
    Opportunity opp = new Opportunity(Name='test opp', StageName='stage', Probability = 95, CloseDate=system.today());
    insert opp;
    opp.Amount = 1000;
    opp.StageName = 'Closed Won';
    update opp;

    // Assign some test values
    String oppId = '1sf2sfs2';
    Decimal oppAmt = 4433.43;
    String oppType = 'Won';

    // Unit test to cover future method
    futureCls.srvcCallout(oppId, oppAmt,oppType);    

    // Unit test to cover http web service
    Test.setMock(HttpCalloutMock.class, new futureClsCalloutMock()); 
    Test.stopTest();

  }
}

You can check for isClosed and Won, by setting the StageName as Closed Won

You can check for isClosed and Lost, by setting the StageName as Closed Lost

For checking if it is not Closed, then set StageName as some other value from the picklist

  • Ankita, In this case opp.StageName = 'Closed Won' could be anything, say opp.StageName = 'abcd' for different salesforce accounts, So have to test for their type IsWon & IsClosed, how can I test for this scenario? – kapil Jul 25 '17 at 13:03
  • Updated the answer – Ankita Jul 25 '17 at 13:46
  • But I have stageName is 'Finalised' of type Closed/Won. I am getting error while setting Closed Won e.g, opp.StageName = 'Closed Won' as you suggested. – kapil Jul 25 '17 at 14:52
0

I think you are in right direction. Couple of things that I notice should be changed are listed below.

Changes

  1. Set your mock prior to calling your future method preferably outside Test.startTest() or Test.stopTest(). Testing methods
  2. Enclose your update opp statement within Test.startTest() and Test.stopTest(). This will make sure that when the trigger runs and future method is executed, it will complete when you call Test.stopTest().
  3. You are using correct test conditions, so you don't need to test the future method explicitly as it will get called when you update the opportunity.
  4. Change the stage name to a valid stage in insert.

Optimizations

  1. Use @testSetup Link to create opportunity/test data.
  2. Your trigger may fail when you update more than 50 records. Limits
  • This answer is no where related to the question. – Ankita Jul 25 '17 at 12:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.