+ Start a Discussion
AnthonyECAnthonyEC 

Code Coverage on Batch Class testMethod

Hi,

having a little trouble getting test coverage on a batch class, odly the test passes like everything was executed, but the execute method isn't covered. Been scratching my head on this one for a while.

 

The class itself is fairly simple, and according to the test, its doing what its suposed to be. Running it in executeanon works as expected as well.

 

Class:

 

 line source
 1  global class updateContactBatch implements Database.Batchable<sObject>
 2  {
 3  
 4   String Query;
 5   List<Contact> uC = new List<Contact>();
 6   List<Master_Tracker__c> uM = new List<Master_Tracker__c>();
 7  
 8   global Database.QueryLocator start(Database.BatchableContext BC)
 9   {
 10   return Database.getQueryLocator(query);
 11   }
 12  
 13   global void execute(Database.BatchableContext BC, List<sObject> scope)
 14   {
 15   for(sObject s : scope)
 16   {
 17   Master_Tracker__c m = (Master_Tracker__c)s;
 18   Contact c = new Contact(Id = m.Contact__c, Send_ExactTarget_Email__c = m.Contact_Exact_Target_Send__c);
 19   m.ContactUpdate__c = false;
 20   uM.add(m);
 21   uC.add(c);
 22   }
 23   update uC;
 24   update uM;
 25   }
 26  
 27   global void finish(Database.BatchableContext BC)
 28   {
 29   System.debug('Finish');
 30   }
 31  
 32   public static testMethod void testBatch()
 33   {
 34  
 35  
 36   List<Contact> cTest = [Select Id from Contact limit 10];
 37   List<Account> aTest = [Select Id from Account limit 1];
 38   List<Master_Tracker__c> mU = new List<Master_Tracker__c>();
 39   for(integer i = 0; i<10; i++)
 40   {
 41   Master_Tracker__c m = new Master_Tracker__c(School_Studies__c = 'testing', Contact__c = cTest[i].Id, BID__c = 'test' + i, Account_Name__c = aTest[0].Id, Offer_Id__c = 'test2' + i, Initiated_Date__c = Date.today());
 42   mU.add(m);
 43   }
 44   insert mU;
 45   Test.StartTest();
 46   updateContactBatch upCon = new updateContactBatch();
 47   List<Master_Tracker__c> testing = [SELECT m.Id, m.Contact__c, m.Contact_Exact_Target_Send__c FROM Master_Tracker__c m WHERE m.ContactUpdate__c = true];
 48   System.debug('the number of returned records are ' + testing.size());
 49   upCon.query = 'SELECT m.Id, m.Contact__c, m.Contact_Exact_Target_Send__c FROM Master_Tracker__c m WHERE m.ContactUpdate__c = true';
 50   Id batchProcessId = Database.executeBatch(upCon);
 51  
 52   Test.StopTest();
 53  
 54   AsyncApexJob a = [Select Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email from AsyncApexJob where Id = :batchProcessId];
 55   System.debug('\n\nFinal results are: '+a);
 56   System.AssertEquals('Completed', a.status);
 57   System.AssertEquals(0, a.NumberOfErrors);
 58  
 59   List<Master_Tracker__c> m2 = [SELECT Id FROM Master_Tracker__c WHERE School_Studies__c = 'testing' and ContactUpdate__c = false];
 60   System.AssertEquals(m2.Size(), 10);
 61   }
 62  
 63  }

 

Here are the results of the Async job:

 

Final results are: AsyncApexJob:{Status=Completed, NumberOfErrors=0, CreatedById=005A0000000S87QIAS, Id=707T0000000EXg3IAG, TotalJobItems=1, JobItemsProcessed=1}

 

The job was submitted and completed, which should mean the code is covered, or at the least, part of it. Any help or places to look would be much apreciated.

 

Best Answer chosen by Admin (Salesforce Developers) 
AnthonyECAnthonyEC

Looks like it was just an issue with the sandbox i was in, refreshing it cleared up all the issues I had. Thank you all for your suggestions.

All Answers

BritishBoyinDCBritishBoyinDC

Not sure how you structure your data but the main thing I can see is that you don't explicitly filter the query you use for your batch test to be only the records that you have just updated in your data setup - and you can only fire the batch once in the test or it will fail...

 

So I would check the system log in case your query is pulling back more than 200 records, or not processing the right records...

AnthonyECAnthonyEC

Thank you @BritishBoyinDC, i've added criteria to the query to look only for records which have been created in the test. I've also limited the query passed to the batch class to only return 10 (limit 10). Still only 40% coverage, and no failures on the test. The system log tells me that only 10 records are returned, and that 10 records are created.

 

Isn't the asynch call the execute method of the batch class? and doesn't the result at the very bottom of the post mean that its was executed sucessfully?

 

BritishBoyinDCBritishBoyinDC

Which lines aren't being tested? I assume it is the main execution lines? If so, that suggests that there isn't any data being passed into the batch to process, in which case the main for loop is never executed.

 

Does the debug statement confirm that the query returns 10 rows?

hitzhitz

Hi, Anthony

 

i have seen your code but not found what query you are using might be u have not defing query. you have directly done return query..

 

global Database.QueryLocator start(Database.BatchableContext BC){
        query = 'select ...... from .......';    // Missing parameter
        return Database.getQueryLocator(query);         
 }

 

after that in your test method try to insert contact , Account and Master_Tracker__c and after that try to update contact and Master_Tracker__c record and execute batch usig below code

 

updateContactBatch batchcontactObj = new updateContactBatch();

Id jobId = Database.executeBatch(batchcontactObj);
System.assertNotEquals(null, jobId);

 

List<YourObject> scope = new List<YourObject>;

.......

......
........

insert scope;

// scope returns List of your query

batchcontactObj.execute(null, (List<SObject>)scope);

batchcontactObj.finish(null);

 

Rajesh ShahRajesh Shah
Hi Anthony, In your query I see that you have used 'where ContactUpdate = true'. However, in the Master Tracker records that you inserted, I do not see the ContactUpdate set to true. I am assuming that it is set to false and hence the query doesn't returns any record making the scope 0 and execute method not called.
AnthonyECAnthonyEC

Yes, its the main execution lines are not covered.

 

Line 47 is the same query i'm passing to the execute method, it returns 10 rows.

 

 47   List<Master_Tracker__c> testing = [SELECT m.Id, m.Contact__c, m.Contact_Exact_Target_Send__c FROM Master_Tracker__c m WHERE m.ContactUpdate__c = true];
 48   System.debug('the number of returned records are ' + testing.size());

 

From the debug log:

 

08:09:15.833|USER_DEBUG|[48]|DEBUG|the number of returned records are 10

 

then the log states this, which I'm pretty sure means that 10 rows were included in the execute batch:

 

08:09:15.833|METHOD_ENTRY|[50]|Database.executeBatch(APEX_OBJECT, Integer)
08:09:16.091|METHOD_EXIT|[50]|Database.executeBatch(APEX_OBJECT, Integer)
08:09:16.091|METHOD_ENTRY|[52]|system.Test.stopTest()
08:09:16.107|CODE_UNIT_STARTED|[EXTERNAL]|01pT0000000CmX7|updateContactBatch
08:09:16.122|METHOD_ENTRY|[15]|BatchableContextImpl.BatchableContextImpl()
08:09:16.122|METHOD_EXIT|[15]|BatchableContextImpl
08:09:16.123|METHOD_ENTRY|[10]|Database.getQueryLocator(String)
08:09:16.124|SOQL_EXECUTE_BEGIN|[10]|Aggregations:0|SELECT m.Id, m.Contact__c, m.Contact_Exact_Target_Send__c FROM Master_Tracker__c m 
08:09:16.165|SOQL_EXECUTE_END|[10]|Rows:10
08:09:16.165|METHOD_EXIT|[10]|Database.getQueryLocator(String)

AnthonyECAnthonyEC

Looks like it was just an issue with the sandbox i was in, refreshing it cleared up all the issues I had. Thank you all for your suggestions.

This was selected as the best answer
sean*harrisonsean*harrison

AnthonyEC,

 

Refreshing the sandbox made the test code start working? More specifically, the query was returning records but the execute method wasn't firing when run from your test class, but refreshing the sandbox mysteriously made the execute method fire?

 

I ask because the same thing is happening to me now. :smileysurprised:

sean*harrisonsean*harrison

I'm seeing this very same thing. In one org, my test covers 100% of the target Batchable class. In another org, the very same code in both the test and target classes does NOT exercise the .execute() method of the Batchable class.

 

The one that works is a production org. The one that does not is an unrelated sandbox org.

 

Here's the code just FYI

 

 

global class MV_testBatchable implements Database.Batchable<sObject>
{
    global final String query;
    
    global MV_testBatchable(String q)
    {
        query = q;
    }
    
    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext BC, List<sObject> scope)
    {
        List<Contact> contacts = (List<Contact>) scope;
                System.debug('YYZ - scopeSize='+scope.size());
                System.debug('RUNNING BATCH EXECUTE');
        for (Contact c : contacts) System.debug('YYZ - '+c.name);
    }
    
    global void finish(Database.BatchableContext BC){}
}

 

 

 

@isTest
private class MV_testBatchableTest 
{
    
    static testMethod void myUnitTest() 
    {
        String q = 'SELECT Id, Name FROM Contact LIMIT 10';
        
        Test.StartTest();
        MV_testBatchable batcher = new MV_testBatchable(q);
        Id batchprocessid = Database.executeBatch(batcher, 10);
        Test.StopTest();
        
        String query = q;
        List<Contact> result = Database.query(query);
        System.debug('YYZ - querySize='+result.size());
        System.assert(result.size()>0);
        System.assert(checkMe(result));
    }
    
    static boolean checkMe(List<Contact> cs)
    {
        Contact c = cs.get(0);
        System.debug('YYZ - c:'+c);
        return true;
    }
}

 

 

 

AnthonyECAnthonyEC

This might be a silly question, but are there enough contacts in the unrelated sand box that meet the criteria?

You might change your test class to just create 10 new contacts and select that 10 to assure that you will have records to work on in your batch class.

sean*harrisonsean*harrison

@AnthonyEC,

 

No, sir! Not a silly question at all because:

 

a) we have to question all our assumptions and

b) in fact, there weren't any Contacts in the sandbox! I foolishly assumed there were as there are something like 10k Accounts...

 

I changed the test code per your suggestion. Alas, it made no difference. The .execute() method still doesn't fire.  See anything else I might be doing wrong?

 

Here's the updated test class:

 

 

@isTest
private class MV_testBatchableTest 
{
    
    static testMethod void myUnitTest() 
    {
        List<Contact> cList = new List<Contact>();
        for (Integer i = 0; i<20; i++)
        {
            Contact c = new Contact(LastName = 'TestContact'+i);
            cList.add(c);
        }
        insert cList;
    
        String q = 'SELECT Id, Name FROM Contact LIMIT 10';
        
        List<Contact> result1 = Database.query(q);
        System.debug('YYZ - querySize='+result1.size());
        System.assert(result1.size()>9);

        Test.StartTest();
        MV_testBatchable batcher = new MV_testBatchable(q);
        Id batchprocessid = Database.executeBatch(batcher, 10);
        Test.StopTest();
        
        List<Contact> result2 = Database.query(q);
        System.debug('YYZ - querySize='+result2.size());
        System.assert(result2.size()>0);
        System.assert(checkC(result2));
    }
    
    static boolean checkC(List<Contact> calls)
    {
        Contact call = calls.get(0);
        System.debug('YYZ - call:'+call);
        return true;
    }
}