You need to sign in to do that
Don't have an account?

12% Code Coverage for a Batch Class
Below is the Test Class for the Batch class in the following snippet of the code. The test coverage stops right here : global Database.QueryLocator start(Database.BatchableContext BC){
In need of guidance and help.
TEST CLASS
@isTest(SeeAllData =true)
private class UpdateEmailOptOutFieldBatchableTest{
static testmethod void testUpdateEmailOptOutFieldBatchable() {
Contact ConObj1 = new Contact();
ConObj1.FirstName = 'Paul';
ConObj1.LastName = 'McCartney';
ConObj1.Email='PM@p.com';
//ConObj1.Id ='0038000001HeyJuDEE';
ConObj1.HasOptedOutOfEmail=False;
//ConObj1.LastModifiedDate =
insert conObj1;
Contact ConObj2 = new Contact();
ConObj2.FirstName = 'John';
ConObj2.LastName = 'Lennon';
ConObj2.Email='PM@p.com';
//ConObj2.Id ='0038000002ImaGiNEE';
ConObj2.HasOptedOutOfEmail=False;
//ConObj2.LastModifiedDate =
insert conObj2;
Contact ConObj3 = new Contact();
ConObj3.FirstName = 'Ringo';
ConObj3.LastName = 'Star';
ConObj3.Email='RS@p.com';
//ConObj3.Id ='0038000003LsdSkYEE';
ConObj3.HasOptedOutOfEmail=False;
//ConObj3.LastModifiedDate =
insert conObj3;
Contact ConObj4 = new Contact();
ConObj4.FirstName = 'George';
ConObj4.LastName = 'Harrison';
ConObj4.Email='RS@p.com';
//ConObj4.Id ='0038000004GenTlYEE';
ConObj4.HasOptedOutOfEmail=True;
//ConObj4.LastModifiedDate =
insert conObj4;
Contact ConObj5 = new Contact();
ConObj5.FirstName = 'Led';
ConObj5.LastName = 'Zeppelin';
ConObj5.Email='LZ@p.com';
//ConObj5.Id ='0038000004HeaVeNNN';
ConObj5.HasOptedOutOfEmail=False;
//ConObj5.LastModifiedDate =
insert conObj5;
Contact ConObj6 = new Contact();
ConObj6.FirstName = 'Jimi';
ConObj6.LastName = 'Hendrix';
ConObj6.Email='LZ@p.com';
//ConObj6.Id ='0038000004CasTlEEE';
ConObj6.HasOptedOutOfEmail=True;
//ConObj6.LastModifiedDate =
insert conObj6;
List<Contact> ContactListall = new List<Contact>();
ContactListall.add(conObj1);
ContactListall.add(conObj2);
ContactListall.add(conObj3);
ContactListall.add(conObj4);
ContactListall.add(conObj5);
ContactListall.add(conObj6);
Test.startTest();
//String query = 'SELECT Id, Name, Email, HasOptedOutOfEmail, LastModifiedDate from CONTACT';
//UpdateEmailOptOutFieldBatchable objUpdateEmailOptOutFieldBatchable = new UpdateEmailOptOutFieldBatchable(query);
UpdateEmailOptOutFieldBatchable objUpdateEmailOptOutFieldBatchable = new UpdateEmailOptOutFieldBatchable();
ID batchprocessid = Database.executeBatch(objUpdateEmailOptOutFieldBatchable);
System.abortJob(batchprocessid);
Test.stopTest();
}
}
BATCH CLASS
global Class UpdateEmailOptOutFieldBatchable implements Database.Batchable<sObject>{
// declaring the variable
global final String query;
/* Constructor method to fetch contacts from the database*/
global UpdateEmailOptOutFieldBatchable(){
query = 'SELECT Id, Name, Email, HasOptedOutOfEmail, LastModifiedDate from CONTACT ORDER BY LastModifiedDate DESC';
}
/*Start method to be invoked*/
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Contact> allContactList)
{
// declaring the variables
List <Contact> ContactsToUpdate = new List<Contact>();
Set <String> ContactIDsToUpdate = new Set<String>();
for(integer i=0; i<allContactList.size()-1; i++)
{
for(integer j=i+1; j<allContactList.size()-1; j++)
{
If (allContactList[i].email == allContactList[j].email && ContactIDsToUpdate.contains(allContactList[j].Id)==False)
{
ContactIDsToUpdate.add(allContactList[j].Id);
allContactList[j].HasOptedOutOfEmail=allContactList[i].HasOptedOutOfEmail;
ContactsToUpdate.add(allContactList[j]);
}
}
}
If (ContactsToUpdate.isempty()==False)
{
update ContactsToUpdate;
}
}
global void finish(Database.BatchableContext BC){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[]{'rkshrest@gmail.com'});
mail.setReplyTo('rkshrest@gmail.com');
mail.setSenderDisplayName('Batch Processing');
mail.setSubject('Batch Process Completed');
mail.setPlainTextBody('Batch Process of Email Opt Out field update for duplicate contact records has completed');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
}
}
We should probably take a step back and observe what's going on before we go down this road much further. Assuming I'm reading your code correctly, it appears that you're trying to toggle "email opt out" for all contacts by email when the value changes. It would seem to me that your best choice would be a trigger, not a batch class, which is not selective enough anyways. Try this:
//////////////////////////
That said, if you want to use a batch class, you'll need to think it through again; your code won't work well because of boundary issues, incorrect ordering of query, non-optimized query, etc. Here's some helpful tidbits:
* Filter your query at least by "Email != null" (I do this in my trigger by removing the empty keys from the email map.
* Order your query by Email, then by LastModifiedDate. This will increase the chances that relevant contacts will be next to each other.
* Consider running a query inside your execute method to obtain data (increases accuracy).
Here's a possible solution:
Fully implemented, just use your test method on it with name changes, should be okay.
Note the use of maps instead of nested for loops ( for ... for ... ), a query to check for the most recent value, etc. Everything's commented, so it should be fairly easy to understand.
All Answers
Don't abort the job; this means it won't be executed (and remember, it runs in a "sandbox" mode, so no data will actually be modified). Asynchronous code runs when "Test.stopTest()" is called.
SF,
Thanks for your reply.
I did commented out the system.abort line.
The code coverage increased to 20%.
However, a test failure occured with following message:
Method Name:
UpdateEmailOptOutFieldBatchableTest.testUpdateEmailOptOutFieldBatchable
Message:
System.UnexpectedException: No more than one executeBatch can be called from within a testmethod. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.
Stack Trace:
External entry point
Please help!!
DR
Like is says, you need to make sure that you're returning no more than one batch worth of data (200 rows) when testing. Usually this means passing a parameter into the batch class so that it uses a different query depending on if you're in test mode or not. Try this:
Then, change your test code to use "new UpdateEmailOptOutFieldBatchable(true)" instead of the default constructor.
SF,
Thank you so much for your time and consideration.
So in order to test this batch class, I created a contact and it's duplicate contacts(i.e. same email id) with different values for the Email Opt Out field.
I executed the batch from developer console using,
Database.executeBatch(new UpdateEmailOptOutFieldBatchable());
All the batches processed without failure. However, the duplicate contacts were not updated :(
Can you please give a one last look to my batch apex code to see if I have missed some logic?
Thanks!!!!
Help Please!!
We should probably take a step back and observe what's going on before we go down this road much further. Assuming I'm reading your code correctly, it appears that you're trying to toggle "email opt out" for all contacts by email when the value changes. It would seem to me that your best choice would be a trigger, not a batch class, which is not selective enough anyways. Try this:
//////////////////////////
That said, if you want to use a batch class, you'll need to think it through again; your code won't work well because of boundary issues, incorrect ordering of query, non-optimized query, etc. Here's some helpful tidbits:
* Filter your query at least by "Email != null" (I do this in my trigger by removing the empty keys from the email map.
* Order your query by Email, then by LastModifiedDate. This will increase the chances that relevant contacts will be next to each other.
* Consider running a query inside your execute method to obtain data (increases accuracy).
Here's a possible solution:
Fully implemented, just use your test method on it with name changes, should be okay.
Note the use of maps instead of nested for loops ( for ... for ... ), a query to check for the most recent value, etc. Everything's commented, so it should be fairly easy to understand.
I can't thank you enough for helping me out in this magnitude!!
It's my christmas gift :) Happy Holidays!!