0

I have some code in my catch block for both @Post and @Get methods. I need to cover catch block to get to 75% for GET, got catch block covered for POST

Here is an example :

// POST

my JSON : 
[
    {
        "somevalue" : "abcd",
        "customerId" : "12345"
    },
    {
        "somevalue" : "xyz",
        "customerId" : "78901"
    }
]

I have created an API class for the above.

Logic has been handled in main class with try and catch block below

Main class :

@RestResource(urlmapping='/someendpoint/*')
global with sharing class Sample
{
    public static String responseJson = '';
    @HttpPost
    global static void doObjectCreation()
    {
        // local variables
        Boolean isException = false;
        String requestJson;

        RestRequest request = RestContext.request;
        RestResponse response = RestContext.response;
        requestJson = request.requestBody.toString();
        try
        {
            String agencyCode = request.requestURI.substring(request.requestURI.lastIndexOf('/')+1);
            system.debug('agencyCode @@'+agencyCode);

            list<creationAPI> qcAPI = creationAPI.parse(requestJson);
            system.debug('request @@'+qcAPI);

            // check incoming api is valid
            if(qcAPI != null){ // DO Business logic and send response }
        }    
        catch(Exception ex)
        {
            system.debug(' Exception found @@ ' + ex.getMessage());

            isException = true;
            CreateLogs.insertLogRec('Log Exception Logs Rec Type', '', '',
                                    'doObjectCreation', (responseJson.length() > 32768) ? responseJson.substring(0,32767) : responseJson,
                                    String.valueOf(''), true,'', ex);
            // DO some business logic and send response
        }
    }
}

Test Class :

@isTest
public class Sample_Test {

    @testSetup
    public static void setup() {// insert objects here}

    @isTest
    public static void ObjectCreation()
    {
        list<creationAPI> myApi = creationAPI_Test.testParse(); // returns API list
        Sample_Test.restLogic(myApi,null);

        Test.startTest();
            Sample.doObjectCreation();
        Test.stopTest();
    }    

    @isTest
    public static void testwithExcepJSON()
    {
        try{
            system.debug('Inside JSON Excep');
            String myExcepJson = '';
            QSample_Test.restLogic(null,myExcepJson);

            Test.startTest();
                Sample.doObjectCreation();
            Test.stopTest();
        }
        catch(Exception myException){
            system.debug('inside exception test'+myException.getTypeName());
        }
    }

    public static void restLogic(list<creationAPI> theApi, String theExcepJson){

        RestRequest req = new RestRequest(); 
        RestResponse res = new RestResponse();

        req.requestURI = '/services/apexrest/someendpoint/1010101';  
        req.httpMethod = 'POST';
        req.requestBody = (theApi != null) ? Blob.valueOf(JSON.serializePretty(theApi)) : 
                          (theExcepJson != null) ? Blob.valueOf(theExcepJson) : null ;

        RestContext.request = req;
        RestContext.response = res;
    }  
}

The above class covers my catch block and working as expected. I was able to cover for Post as it had requestBody , but not able to cover for Get.

Here is the example :

// GET

// NO request Body

Main class :

@RestResource(urlmapping='/GetEndpoint/*')
global with sharing class SampleGET
{
    public static String responseJson = '';
    @HttpGet
    global static void doObjectFetch()
    {
        // local variables
        Boolean isException = false;

        RestRequest request = RestContext.request;
        RestResponse response = RestContext.response;
        try
        {
            String agencyCode = request.requestURI.substring(request.requestURI.lastIndexOf('/')+1);
            system.debug('agencyCode @@'+agencyCode);

            // DO Business logic and send response
        }    
        catch(Exception ex)
        {
            system.debug(' Exception found @@ ' + ex.getMessage());

            isException = true;
            CreateLogs.insertLogRec('Log Exception Logs Rec Type', '', '',
                                    'doObjectFetch', (responseJson.length() > 32768) ? responseJson.substring(0,32767) : responseJson,
                                    String.valueOf(''), true,'', ex);
            // DO some business logic and send response
        }
    }
}

Test Class :

@isTest
public class SampleGET_Test {

    @testSetup
    public static void setup() {// insert objects here}

    // this one works and covers code
    @isTest
    public static void ObjectRetrieval()
    {
        SampleGET_Test.restLogic('2020202');

        Test.startTest();
            SampleGET.doObjectFetch();
        Test.stopTest();
    }    

    @isTest
    public static void testwithExcepJSON()
    {
        try{
            Test.startTest();

            RestRequest req = new RestRequest(); 
            RestResponse res = new RestResponse();

            //actual end point is : GetEndpoint
            // to get exception I'm giving dummy end point - dummyUrl
            req.requestURI = '/services/apexrest/dummyUrl/1010101';
            req.httpMethod = 'GET';

            RestContext.request = req;
            RestContext.response = res;

            SampleGET.doObjectFetch();
            Test.stopTest();
        }
        catch(Exception myException){
            system.debug('inside exception test'+myException.getTypeName());
        }
    }

    public static void restLogic(String agencyCode){

        RestRequest req = new RestRequest(); 
        RestResponse res = new RestResponse();

        req.requestURI = '/services/apexrest/GetEndpoint/'+agencyCode;  
        req.httpMethod = 'GET';

        RestContext.request = req;
        RestContext.response = res;
    }  

}

I'm not sure what I need to do in that exception method for Get.

2 Answers 2

2

You can try setting your requestURI to null, so that it raises the null pointer exception in your HTTP GET method which will lead to covering the exception block.

req.requestURI = null;

So your test method should set the requestURI as null, but you also need to make sure that you do assertion in this test method i.e. you can check if the log record which you are inserting in catch block is inserted.

Also, there is no need to have try catch block in your test method, as exceptions will be handled in the main class, still I have kept it in the below example, but you can remove that block.

@isTest
public static void testwithExcepJSON()
{
    try{
        Test.startTest();

        RestRequest req = new RestRequest(); 
        RestResponse res = new RestResponse();

        //actual end point is : GetEndpoint
        // to get exception I'm giving dummy end point - dummyUrl
        //req.requestURI = '/services/apexrest/dummyUrl/1010101';
        req.requestURI = null;
        req.httpMethod = 'GET';

        RestContext.request = req;
        RestContext.response = res;

        SampleGET.doObjectFetch();
        Test.stopTest();
        System.assertEquals(1, [select count() from Log__c]);
    }
    catch(Exception myException){
        system.debug('inside exception test'+myException.getTypeName());
    }
}
1
  • Thank you. I was able to cover the exception part. I also covered the JSON Exception too.
    – AjaySFDC
    Commented Mar 14, 2019 at 0:38
0

An ideal pattern to use to test exceptions is the fflib Service Layer and ApexMocks

While the scope of this is bigger than the answer format permits (see the links above), you will

Create a Service class for the business logic within the try. You'll need an entry in the Application.cls for your service class.

try {
  MyService.doSomething(..);
}
catch (Exception e) { ..}

Write your testmethod to mock an exception so you can test your catch block

// Given mocking framework and mock exception
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_ApexMocks.ApexMocksException mockEx   = new fflib_ApexMocks.ApexMocksException('mock MyService Exception');

// Given mock service that throws a mockException
MyServiceImpl mockMyService = (MyServiceImpl) mocks.mock(MyServiceImpl.class);
mocks.startStubbing();
(IMyService) mocks.doThrowWhen(mockEx,mockMyService));
mocks.stopStubbing();

// Inject the mock service into the factory
Application.Service.setMock(IMyService.class,mockMyService);



// When GET
Test.startTest();
...code to invoke doObjectFetch
Test.stopTest()

// Then verify exception code path yielded expected results
...

How does this work?

By using the fflib Service layer, your PROD code gets from the Application.Service factory a production object of the MyService. But in the testmethod, you mock your own service and tell the mock implementation to throw an exception.

When your @HttpGet method is invoked after Test.startTest(), the call to MyService.doSomething(..) calls the mocked service which throws an exception. Your test doesn't have to jump through hoops to coerce an exception by setting values to null or dividing by zero or whatnot.

2
  • Will this be complicated to do ? I haven't worked on Service layer. I will try to implement this. But i got that working with the above answer too. Thanks ..
    – AjaySFDC
    Commented Mar 14, 2019 at 0:39
  • @AjaySFDC - using the fflib pattern and apexmocks is an investment in time that is worth doing if you a) have an org where apex architecture is important (rather than a handful of triggers, etc for localized feats not doable via point and click); b) expect to be working on this org for a long time so laying a good foundation makes sense; or c) you care about taking your apex skills to the next level
    – cropredy
    Commented Mar 14, 2019 at 16:53

You must log in to answer this question.

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