I am a newbie in salesforce. I have a batch apex class. I wrote a test class for the class and my test method is passed but am not getting the code coverage. I have covered 42% of the code.
Apex Class:
global class EF_OKTA_Queue_Batch implements Database.Batchable <sObject>, Database.AllowsCallouts
{
private String query;
private list<EF_OKTA_Queue__c> lstoktaQueueUpdate = new list<EF_OKTA_Queue__c>();
global EF_OKTA_Queue_Batch ()
{
query = EF_SOQL_Statements__c.getValues('EF_OKTA_Queue_Batch_Query').Type__c + ' ' + EF_SOQL_Statements__c.getValues('EF_OKTA_Queue_Batch_Query').Fields__c +
EF_SOQL_Statements__c.getValues('EF_OKTA_Queue_Batch_Query').Relationship_fields__c + ' from ' + EF_SOQL_Statements__c.getValues('EF_OKTA_Queue_Batch_Query').Object__c +
' where ' + EF_SOQL_Statements__c.getValues('EF_OKTA_Queue_Batch_Query').Filter__c;
}
global Database.QueryLocator start(Database.BatchableContext bc)
{
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List <EF_OKTA_Queue__c> scope)
{
List<String> queueWithEmptyURL = new List<String>();
List<EF_OKTA_Queue__c> itemsToUpdate = new List<EF_OKTA_Queue__c>();
Map<String, String> errorsToLog = new Map<String, String>();
EF_OKTA_RESTAPI objEFAPI = null;
for (EF_OKTA_Queue__c oktaQueue: scope) {
if (oktaQueue.OKTA_URL__c == null || oktaQueue.OKTA_URL__c.trim() == '') {
queueWithEmptyURL.add(oktaQueue.id);
continue;
}
// After 15 minutes (Scheduled Job) mark status to complete
if (oktaQueue.EF_Requested_Resource__r.EF_Resource_Metadata__r.Type__c == 'HYBRID AUTOMATED' && oktaQueue.CreatedDate.addMinutes(15) < Datetime.now()) {
// additional logic in trigger
oktaQueue.Status__c = 'Complete';
} else if (oktaQueue.EF_Requested_Resource__r.EF_Resource_Metadata__r.Type__c == 'HYBRID' && oktaQueue.CreatedDate.addMinutes(15) < Datetime.now()) {
// additional logic in trigger
oktaQueue.Status__c = 'Complete';
} else if (oktaQueue.EF_Requested_Resource__r.EF_Resource_Metadata__r.Type__c == 'AUTOMATED') {
// API Class object
objEFAPI = new EF_OKTA_RESTAPI();
// disable error log to avoid problems with executing a call, storing error record and getting an exception when trying to execute second call
objEFAPI.setDisableErrorLog(true);
// Execute call and query for current user data / profile
String currentJSON = objEFAPI.getOKTAAttributes(oktaQueue.OKTA_URL__c);
// extract Synchronisation Status
String status = EF_OKTA_Queue_Batch.getSyncState(currentJSON);
if (status == 'SYNCHRONIZED') {
// sync status is ok so let's mark queue item as complete
oktaQueue.Status__c = 'Complete';
} else {
// not synced yet, let's try some other time ...
oktaQueue.number_tried__c += 1;
// there might be an error so let's log it
if ('' == status) {
errorsToLog.put(oktaQueue.id, currentJSON);
}
}
}
itemsToUpdate.add(oktaQueue);
}
try {
// process queueWithEmptyURL first (cannot do it future)
EF_OKTA_Queue obj = new EF_OKTA_Queue();
obj.execute(queueWithEmptyURL);
// update items that already have url
if (itemsToUpdate.isEmpty() == false) {
update itemsToUpdate;
}
} catch(Exception ex) {
string strError = '';
for (EF_OKTA_Queue__c oktaQueue: scope) {
strError = (strError!='') ? (strError + ',' + oktaQueue.id) : oktaQueue.id;
}
EF_Error_Log.logException('EF_OKTA_Queue_Batch', strError, 'DML', 'HIGH', ex.getMessage() + '\n\nStack Trace:\n' + ex.getStackTraceString());
}
// if there were some invalid responses log them as errors into the log object
if (errorsToLog.isEmpty() == false) {
String message = '';
for (String queueId : errorsToLog.keySet()) {
message = errorsToLog.get(queueId);
if (message == '') {
message = 'JSON Response was empty ...';
}
EF_Error_Log.logException('EF_OKTA_Queue_Batch', queueId, 'OKTA', 'HIGH', message);
}
}
}
global void finish(Database.BatchableContext BC)
{
//Final Actions: requirements not defined yet will update the code
}
global static string getSyncState(string jsonString)
{
string status = '';
if (jsonString == null || jsonString.trim() == '') {
return status;
}
try {
Map<String, Object> tmp = (Map<String, Object>) JSON.deserializeUntyped(jsonString);
if (false == tmp.containsKey('syncState')) {
return status;
}
status = (String) tmp.get('syncState');
} catch (Exception e) {
// we don't care about the error here, it just means that status is not
// synchronised and we need to repeat the query/request
// json response will be logged by the calling method above
}
return status;
}
}
Test Class:
@isTest
private class EF_OKTA_Queue_Batch_Test
{
static TestMethod void OKTAQueueBatchTest()
{
Database.QueryLocator QueryLoc;
Database.BatchableContext BatchCont;
List<EF_OKTA_Queue__c> lstOKTAQ= new List<EF_OKTA_Queue__c>();
EF_SOQL_Statements__c objStmts= EF_DataFactory_Utility.insert_EF_SOQL_Statements();
EF_OKTA_Queue_Batch ObjOKTAQbatch = new EF_OKTA_Queue_Batch();
ID batchprocessid = Database.executeBatch(ObjOKTAQbatch,200);
System.debug('######EXECUTE BATCH'+ batchprocessid);
List<EF_OKTA_Queue__c> lstOKTAQueue = new List<EF_OKTA_Queue__c>();
lstOKTAQueue = EF_DataFactory_Utility.insert_EF_OKTA_Queue();
insert lstOKTAQueue;
QueryLoc= ObjOKTAQbatch.start(BatchCont);
System.debug(BatchCont);
Database.QueryLocatorIterator QueryIterate = QueryLoc.iterator();
while (QueryIterate.hasNext())
{
EF_OKTA_Queue__c objQueue = (EF_OKTA_Queue__c)QueryIterate.next();
System.debug(objQueue);
System.debug(objQueue.OKTA_URL__c);
lstOKTAQ.add(objQueue);
}
ObjOKTAQbatch.execute(BatchCont, lstOKTAQ);
ObjOKTAQbatch.finish(BatchCont);
String json = '{'+
' \"items\": ['+
' {'+
' \"id\": \"pn0\",'+
' \"syncState\": \"0\",'+
' \"managerID\": \"pc0\"'+
' },'+
' {'+
' \"id\": \"pn1\",'+
' \"syncState\": \"1\",'+
' \"managerID\": \"pc1\"'+
' },'+
' {'+
' \"id\": \"pn2\",'+
' \"syncState\": \"2\",'+
' \"managerID\": \"pc2\"'+
' }'+
' ]'+
'}';
EF_OKTA_Queue_Batch.getSyncState(json);
}
}
Please help me out.
Thanks in Advance!!!
Attribution to: Cool Damsel
Possible Suggestion/Solution #1
There are a lot of branches in you class that are not being covered by this single test. For example "if (errorsToLog.isEmpty() == false)" - has about 7 lines that are not being covered.
You need to write further test methods with data that will run down these routes.
Follow Jason Clark's answer to access your coverage in the Developer Console so you get to a view of your class something like this:
And this will help you work out which routes you need to test.
I would recommend replicating you test method (leaving the original in tact) and then alter your JSON and the other data dependant code to meet the different conditions (again, much like Jason Clark said! [I did vote your answer Jason!])
Attribution to: Simon Lawrence
Possible Suggestion/Solution #2
You can see which lines of your class are covered and which are not by using the Developer Console, see the salesforce help for details on how to view coverage and to see a screenshot of the coverage view. Add additional test methods to cover each branch of your conditional logic. If you aren't sure how to test a certain block of code, ask yourself what conditions cause that code to run under normal circumstances, and design a test to replicate those conditions. Also remember that these are meant to be unit tests, not integration tests; it's fine to create data in your tests that tests only a certain part of your process.
Some of your conditionals are based on record CreatedDate values. These can be hard to test because you can't set the CreatedDate directly, however, if you load test data from a static resource you can include CreatedDate in the csv file.
Sometimes you may not be able to test every line of code within a file, for example, some error conditions can be hard to replicate in a test. The requirement for deployment to production is 75% org-wide coverage; individual files can be lower than 75% if necessary as long as the org-wide coverage is ok.
Attribution to: Jason Clark
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/30352