0

All, need help with test class on Batch apex. Below is batch apex code which make 2 callouts (for Token and actual data) however i`m not able to get test coverege on this class. All I have is 7% coverage. Can someone please help?

    global class CalloutsAccounts implements Database.Batchable<sObject>,Database.AllowsCallouts{


   global Database.QueryLocator start(Database.BatchableContext BC){
        String query =  'SELECT Id FROM Account LIMIT 1';
        return Database.getQueryLocator(query); 
   }

   global void execute(Database.BatchableContext BC, List<Account> scope){
        HttpRequest obj = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        String reqBody = '{ "user": "Username", "passwd": "user_password" }';
        obj.setMethod('POST');
        obj.setHeader('Content-Type','application/json');
        obj.setEndPoint('https://test.samplepoint.com/api/UserSrvs.svc/Login');
        obj.setBody(reqBody);
        obj.getheader('Auth-Token');
        res = http.send(obj);

                authtoken objAuthenticationInfo = (authtoken)JSON.deserialize(res.getbody(), authtoken.class);
String token = res.getHeader('Auth-Token');


        Http h1 = new Http();
        HttpRequest req1 = new HttpRequest();
        String reqBody2 = ' {"Accountype" : "workforce"}'; 
        req1.setHeader('Auth-Token', token);
        req1.setHeader('Content-Type','application/json');
        req1.setMethod('POST');
         req1.setBody(reqBody2);

        req1.setEndpoint('https://test.samplepoint.com/api/accservices.svc/accountfeed');
        HttpResponse res1 = h1.send(req1);



                   JSONParser parser = JSON.createParser(res1.getBody());
                    parser.nextToken();
                     parser.nextValue();

                    String fieldName = parser.getCurrentName();
                    String fieldValue = parser.getText(); 

    accParser deserializeResults3 =  new accParser ();
    deserializeResults3 = (accParser)System.JSON.deserialize(fieldValue, accParser.class);
     List < accParser.cls_account> advisorList = new List< accParser.cls_account>();
    advisorList = deserializeResults3.root.accounts.account;

           Map <Decimal,Id> AdvisorMap = New Map  <Decimal,Id>   ();

        List <Account> advisorAccList = [SELECT Id, Fact_ID__c, RecordTypeID FROM Account WHERE RecordTypeid = '0124100000091Ho'];

        For (Account Acs : advisorAccList) {
            If (Acs.Fact_ID__c != null)
            AdvisorMap.put(Acs.Fact_ID__c, Acs.ID);
                }


             Map <String,Id> HouseholdMap = New Map  <String,Id>   ();

        List <Account> advisorAccList1 = [SELECT Id, SSCN__c, RecordTypeID FROM Account WHERE RecordTypeid = '012410000009Il6'];

        For (Account Acs1 : advisorAccList1) {
            If (Acs1.SSCN__c != null)
            HouseholdMap.put(Acs1.SSCN__c, Acs1.ID);
            system.debug('@@@'+HouseholdMap);
                }



List<Financial_Account__c> lstAccount = new List<Financial_Account__c>();
for(accountParser.cls_account cand : advisorList){
    Financial_Account__c PFA = New Financial_Account__c();
    //PFA.Cirrus_Unique_ID__c =  cand.account_id;

    //Map Advisor Lookup
   PFA.Advisor_ID__c = cand.advisor_id; 
   PFA.Advisor__c = AdvisorMap.get(PFA.Advisor_ID__c );  

    //Map Household Client Lookup
    PFA.Household_ID2__c = cand.household_id;
   if (HouseholdMap.get(PFA.Household_ID2__c) == null) {
       PFA.Client__c = '0013C000003Ywet'; 
} else if (PFA.Household_ID2__c != null) {
         PFA.Client__c = HouseholdMap.get(PFA.Household_ID2__c);  
}




    PFA.Unique_ID__c =  cand.account_id;
    PFA.Financial_Account_Number__c =  cand.accountnum;
    PFA.Account_Type__c =  cand.account;
    PFA.Tax_Status__c=  cand.taxablestatus;
    PFA.Investment_Objective__c =  cand.objective;
    if (cand.inception_date != null) {
    PFA.Account_Opening__c = date.parse(cand.inception);
        }
        if (cand.perf_begin_date != null) {
    PFA.perf_begin_date__c = date.parse(cand.perfdate);
        }
    // if (cand.household_id != null) {
  //  PFA.Household_ID__c = cand.housedate_id;
  //      }
    PFA.Account_Type__c =  cand.account_type;
   // PFA.Client__c =  '0013C000003CRTr'; LOOKUP TO ACCOUNTS
    PFA.compute_flg__c = cand.compute_flg;
    PFA.Account_Description__c = cand.description;
    PFA.fwc_hh_id__c = cand.fwc_hh_id;
        if (cand.termination_date != null) {
    PFA.termination_date__C = date.parse(cand.termination_date);
        }
        if (cand.last_date != null) {
    PFA.last_date__c = date.parse(cand.last_date);
        }
    PFA.Custodian_Id__c = cand.custodian_id;
    PFA.billing_account_num__c = cand.billing_account_num;
    PFA.rebal_method__c = cand.rebal_method;




    lstAccount.add(PFA);
}


Boolean isUpsertfirstTime = true;
try {
    upsert lstAccount Financial_Account_Number__c;
}catch (DMLException e) {
                System.debug('Re-trying');
                if(isUpsertfirstTime){
                        upsert lstAccount Financial_Account_Number__c;
                                isUpsertfirstTime = false;
              }
}


   }       

   global void finish(Database.BatchableContext BC){
              CalloutsAccounts2 myaccBatch = new CalloutsAccounts2();
      Id batchProcessId = Database.executeBatch(myacctBatch);

   }
}

Mock:

@isTest
global class MockHttpResponseGenerator implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest req) {
        // Optionally, only send a mock response for a specific endpoint
        // and method.
               System.assertEquals('https://test.samplepoint.com/api/UserSrvs.svc/', req.getEndpoint());
        System.assertEquals('POST', req.getMethod()); 

        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
res.setBody(''{ "user": "Username", "passwd": "user_password" }');
        res.setHeader('Auth-Token', '3+yV8B+7iSTu7Oj4alK4/fJPY1a5VRhAre6jG5vx6kDTXMOENFWJqAIQpuYE8nOdLwDmQBdo=');
 res.setStatusCode(200);         
        return res;
    }
}

TEst Class:

@isTest
private class CalloutClassTest {
     @isTest static void testCallout() {
        // Set mock callout class 

        Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
        Test.startTest();
        Database.executeBatch(new CalloutsAccounts(), 100);
        Test.stopTest();

    }
2
  • I don't see you inserting an Account record in your test class – d_k Oct 21 '16 at 12:19
  • You need to have a test record so that your start method can get it in the Query – d_k Oct 21 '16 at 12:20
3

Your test class is missing data for it to actually use. In this instance, your batch is using this query:

SELECT Id FROM Account LIMIT 1

Salesforce will be querying for this and think "hey, there's no data to use! There's no point in executing anything because there's nothing to execute over!"

Thus whilst the start() method will get covered, the execute() and finish() methods won't.

All I have is 7% coverage

This, I suspect is your 7%.

So in your test class you'll want to create something like this above your testCallout() method:

@testSetup static void test_data() {
    Account acc = new Account(
        Name = 'My Test Account'
    );

    INSERT acc;
}

This will insert test data for you to use in your test class and thus give your batch class something to process.

I will say I'm confused as to why you're putting a LIMIT 1 on your Batch class' query as it kind of defeats the point of even using a Batch class. Just use:

SELECT Id FROM Account

When you're executing the batch class, you kind of, do this as part of the second parameter:

Database.executeBatch(new CalloutsAccounts(), 100);

Here you're saying, execute this batch and do them over multiple batches of 100 records. There might be 1 batch of 1 records or 100 batches with 10000 records in the total.

Edit As @AdrianLarson points out also, avoid using hard-coded anything. Instead, you'll want to query for the DeveloperName. If you're unsure what that is, you can run a query using workbench or debugging via anonymous apex in the developer console, for example, something like:

RecordType rt = [SELECT Id, DeveloperName FROM RecordType WHERE Id = '0124100000091Ho'];

System.debug('@@@@@@@@@@' + rt.DeveloperName);

In your code you should then query for the RecordType by using that DeveloperName. It's not too dissimillar to the above query:

RecordType rt = [SELECT Id, DeveloperName FROM RecordType WHERE DeveloperName = 'MyRecordType'];

Then in your query reference it, such as below:

List <Account> advisorAccList1 = [SELECT Id, SSCN__c, RecordTypeID FROM Account WHERE RecordTypeid = rt.Id];

You should use DeveloperName because the name is effectively a label that may change and Ids are inconsistent across Sandboxes and Production environments.

7
  • Yeah. Very much missing the point. – Adrian Larson Oct 21 '16 at 12:41
  • @Dan... Thank you for replying. You are right, only start method is being covered. If I remove 'SELECT Id FROM Account LIMIT 1', query part from start method, it gives me an error stating no query in start so I added a small statement. Sorry, I`m new to Apex. is there a better way to deal with this issue? – Tom Simmons Oct 21 '16 at 13:15
  • Also, hard-coded ids are very bad and you should avoid them at all costs. – Adrian Larson Oct 21 '16 at 14:03
  • @TomSimmons Just remove the LIMIT 1 so your query will be SELECT Id FROM Account. – Dan Jones Oct 21 '16 at 14:07
  • @TomSimmons It's also worth noting that Database.getQueryLocator() returns up to 50 million records whereas typical SOQL returns 50k I believe. So unless your database is massive, you've likely nothing to worry about with respect to governor limits. – Dan Jones Oct 21 '16 at 14:41

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.