
Tips to Write Efficient Test Class for Batch Apex
Every line of Apex code written should always be covered by unit tests in Salesforce. This is to ensure that the overall code coverage remains above 75% and also ensures any new code written doesn’t break existing code.
Do you need Test Class for Batch Class in Salesforce?
Yes. Unit Test Classes should ALWAYS be written for Batch Apex Classes as well.
How do you Test a Batch Class?
Often times developers worry that writing a test class for a Batch Apex Class would be a time consuming and difficult task. However, writing a test class for batch class is very similar to writing unit class for a trigger or other apex classes. The basics remain the same and the calling of the main execute method is the only part that differs. In this article, we will ensure all developers reading this can benefit from the tips to write efficient unit test classes for testing batch apex.
Structure of Unit Test:
- Create Test Data
- Start testing by calling the Test.startTest() method
- Then call the execute command of the Batch Class
- End Testing by calling the Test.endTest() method
- Confirm that batch executed successfully by using System.Assert statements.
Writing a Test Class for a Batch
We have written snippets of unit test classes for different use cases that you can come across when writing Batch Apex.
1. Single Record Unit Test
Batch Apex Code
Public Class BatchApexExample implements Database.Batchable<Sobject>{ Public Database.QueryLocator start(Database.BatchableContext bc) { return Database.getQueryLocator('Select Type, Industry from Account'); } Public void execute(Database.BatchableContext bc, List<Account> AccList) { for(Account a : AccList){ if(a.Type =='Personal'){ a.Industry = 'Household'; } } update AccList; } Public void finish(Database.BatchableContext bc){ } }
Unit Test Code
@isTest Private Class BatchApexExampleTest { Static testMethod void testBatchExecuteMethod() { Account a = new Account(); a.Name = 'John Smith'; a.AccountSource = 'Web'; a.AnnualRevenue = 100,000; a.Type = 'Personal'; insert a; Test.startTest(); BatchApexExample batchTest = new BatchApexExample (); Id jobid = Database.executeBatch(batchTest,5); Test.stopTest(); Account acc = [Select Industry from Account where id=: a.Id]; System.assertEquals('Household', acc.Industry); } }
2. Bulk Record Unit Test
Batch Apex Code
Public Class BatchApexExample implements Database.Batchable<Sobject>{ Public Database.QueryLocator start(Database.BatchableContext bc) { return Database.getQueryLocator('Select Type, Industry from Account'); } Public void execute(Database.BatchableContext bc, List<Account> AccList) { for(Account a : AccList){ if(a.Type =='Personal'){ a.Industry = 'Household'; } } update AccList; } Public void finish(Database.BatchableContext bc){ } }
Unit Test Code
@isTest Private Class BatchApexExampleTest { Static testMethod void testBatchExecuteMethod() { List<Account> accList = new List<Account>(); for(Integer i=0; i < 200; i++){ //Iterate through the for loop 200 times and add the integer i after account name to make it unique. a.Name = 'John Smith '+i; a.AccountSource = 'Web'; a.AnnualRevenue = 100,000+i; a.Type = 'Personal'; accList.add(a); } insert accList; Test.startTest(); BatchApexExample batchTest = new BatchApexExample (); Id jobid = Database.executeBatch(batchTest,5); Test.stopTest(); List<Account> acc = new List<Account<>(); acc = [Select Industry from Account where Industry = 'Household']; System.assertEquals(200, acc.size()); } }
3. Batch Callout Unit Test
Batch Class Code
Global Class BatchAccount implements Database.Batchable<sObject>, Database.AllowsCallouts{ Global Database.QueryLocator start(Database.BatchableContext bc){ return Database.getQueryLocator('Select Type, Industry from Account where Type ='Media''); } Global void execute(Database.BatchableContext bc, List<Account> accList) { try{ for (Account acc : accList){ *Insert CallOut Code* if(CalloutResponse.getStatusCode == 200){ acc.Industry = 'Social'; } } update accList; } Global void finish(Database.BatchableContext bc) { } }
Mock Class Code
@isTest global class BatchMock implements HttpCalloutMock { global HTTPResponse response(HTTPRequest req) { HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('Success'); res.setStatusCode(200); return res; } }
Unit Test Code
@isTest Public Class BatchApexTest { Static testMethod void batchTestMethod() { List<Account> accList = new List<Account>(); for(integer i = 0 ; i < 5 ;i++ ) { Account a = new Account(); a.Name = 'John Smith '+i; a.Type = 'Media'; accList.add(a); } insert accList; Test.setMock(HttpCalloutMock.class, new BatchMock()); BatchAccount ba = new BatchAccount (); Test.startTest(); Database.executeBatch(bm,200); Test.stopTest(); List<Account> acc = new List<Account<>(); acc = [Select Industry from Account where Industry = 'Social']; System.assertEquals(200, acc.size()); } }
4. Delete Records through Batch Unit Test
Batch Class Code
Public Class BatchApexExample implements Database.Batchable<Sobject>{ Public Database.QueryLocator start(Database.BatchableContext bc){ return Database.getQueryLocator('Select Type, Industry from Account where Type = 'Media'); } Public void execute(Database.BatchableContext bc, List<Account> AccList){ delete AccList; } Public void finish(Database.BatchableContext bc){ } }
Unit Test Code
@isTest Private Class BatchApexExampleTest{ Static testMethod void testBatchExecuteMethod() { List<Account> accList = new List<Account>(); for(Integer i=0; i < 200; i++){ //Iterate through the for loop 200 times and add the integer i after account name to make it unique. a.Name = 'John Smith '+i; a.Type = 'Media'; accList.add(a); } insert accList; Test.startTest(); BatchApexExample batchTest = new BatchApexExample (); Id jobid = Database.executeBatch(batchTest,5); Test.stopTest(); List<Account> acc = new List<Account<>(); acc = [Select Industry from Account where Type = 'Media']; System.assertEquals(0, acc.size()); } }
Conclusion
The above example are proof that writing unit test for Batch Apex are as straightforward as writing unit test for any other type of apex. Ideally, Unit test coverage should be such that it covers all executable lines of code however if that is not possible then one should aim for at least 90% code coverage per class.