0

I wrote a batch class that runs whenever a new sandbox is being refreshed. it takes all the contacts' email addresses and changes them from user@gmail.com to user@example.com. In addition, it checks whether the batch is being executed in production (i.e. the URL contains the eu3 (our production's server)),so if the BaseURL contains 'eu3' such as eu3.salesforce.com then it throws a custom exception.

The batch works, but I'm still struggling to write a test class that will get a high code coverage (currently I get 68%).

It seems that I cannot cover the Exception I wrote + the send email action at the finish method (see the screenshots).

global class changeEmailAddressesToExampleSandbox implements Database.Batchable<sObject>, Database.Stateful {

private List<Contact> contactsEmails;
private String tempEmail;
private String query;
//private Integer totalNumOfContacts;
private Integer total;
private Integer modified;

global changeEmailAddressesToExampleSandbox () {

    contactsEmails = new List<Contact>();
    query = 'SELECT email FROM Contact';
    tempEmail=' ';
    total = 0;
    modified = 0;
    //totalNumOfContacts=[select count() from contact]; //Too Many SOQL queries

}
global Database.QueryLocator start(Database.BatchableContext BC) {
    return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Contact> scope) { //changed Sobject to Contact

    String newEmailDomain = '@example.com';    

    // Check if it's production 
    String sfdcBaseURL = URL.getSalesforceBaseUrl().toExternalForm();
    System.debug('Base URL: ' + sfdcBaseURL );
   if(sfdcBaseURL.contains('eu3'))
      throw new ProductionException('Cannot execute code in production!'); 


    for (Contact con : scope){
        String tempEmail = con.Email;
        if(!String.isEmpty(tempEmail) && !tempEmail.contains('@example.com')&&tempEmail.length()<70){ //tempEmail.length<70 because STRING_TOO_LONG error
            tempEmail = tempEmail.split('@')[0];
            tempEmail += newEmailDomain;
            con.Email = tempEmail;
            contactsEmails.add(con);
        }
    }
    update contactsEmails;

    modified += contactsEmails.size();
    total += scope.size();
}
global void finish(Database.BatchableContext BC) {

    if (!Test.isRunningTest()){
    Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
    message.toAddresses = new String[] { 'testmoshebarak@gmail.com'};
    message.optOutPolicy = 'FILTER';
    message.subject = 'Email From Batch class changeEmailAddressesToExampleInSandbox';
    message.plainTextBody = ''
    + 'All contacts\' emails have been modified successfully ' +'\n'
    + 'The total number of contacts in the Sandbox is '
    + total + '\n'
    + modified +' contacts were updated'
    ;
    Messaging.SingleEmailMessage[] messages =   new List<Messaging.SingleEmailMessage> {message};
    Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);

    if (results[0].success) {
        System.debug('The email was sent successfully.');
        } else {
            System.debug('The email failed to send: ' + results[0].errors[0].message);
        }

    }
}
    public class ProductionException extends Exception {}
}

See Screenshots: Class part 1 Class part 2

Test Class:

@isTest

private class changeEmailAddressesToExampleSandboxTest {

@isTest static void test_positive() {
    Account acc = new Account(Name='Satyricon');
    insert acc;
    Contact con = new Contact(AccountId=acc.id,LastName='Satyr',Email='satyr@gmail.com');
    insert con;
    Test.startTest();
    changeEmailAddressesToExampleSandbox sandbox = new changeEmailAddressesToExampleSandbox();
    Database.executeBatch(sandbox);
    Test.stopTest();
    System.assertEquals('satyr@example.com',[SELECT email FROM Contact WHERE id=:con.id].email);




}

@isTest static void test_negative() {

    Test.startTest();
    String testURL = 'https://eu3.salesforce.com';
    Test.setCurrentPageReference(new PageReference(testURL));
    try{
    changeEmailAddressesToExampleSandbox sandbox = new changeEmailAddressesToExampleSandbox();
    Database.executeBatch(sandbox);
    }
    catch(Exception e){
        System.assert(e.getMessage().contains('Cannot execute code in production!'),e.getMessage());
    }
}

Can someone help me? How can I cover the Exception and the send email action in my test class?

1

For your first method you need some additional method or property to make it possible to substitute production URL for test

@testVisible static String baseURL { get {
    if ( baseURL == null )
        baseURL = URL.getSalesforceBaseUrl().toExternalForm();
    return baseURL;
} set; }


global void execute(Database.BatchableContext BC, List<Contact> scope) { //changed Sobject to Contact

String newEmailDomain = '@example.com';    

// Check if it's production 
System.debug('Base URL: ' + baseURL );
if(baseURL.contains('eu3'))
  throw new ProductionException('Cannot execute code in production!'); 


for (Contact con : scope){
    String tempEmail = con.Email;
    if(!String.isEmpty(tempEmail) && !tempEmail.contains('@example.com')&&tempEmail.length()<70){ //tempEmail.length<70 because STRING_TOO_LONG error
        tempEmail = tempEmail.split('@')[0];
        tempEmail += newEmailDomain;
        con.Email = tempEmail;
        contactsEmails.add(con);
    }
}
update contactsEmails;

modified += contactsEmails.size();
total += scope.size();

}

Then in your test you can create a separate method to cover exceptional case

@isTest static void test_negative() {

Test.startTest();
changeEmailAddressesToExampleSandbox.baseURL = 'https://eu3.salesforce.com';
try{
changeEmailAddressesToExampleSandbox sandbox = new changeEmailAddressesToExampleSandbox();
Database.executeBatch(sandbox);
}
catch(Exception e){
    System.assert(e.getMessage().contains('Cannot execute code in production!'),e.getMessage());
}
}

Also you should remove check if (!Test.isRunningTest()){ in your finish method, otherwise you wouldn't get coverage for those lines

global void finish(Database.BatchableContext BC) {
Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
message.toAddresses = new String[] { 'testmoshebarak@gmail.com'};
message.optOutPolicy = 'FILTER';
message.subject = 'Email From Batch class changeEmailAddressesToExampleInSandbox';
message.plainTextBody = ''
+ 'All contacts\' emails have been modified successfully ' +'\n'
+ 'The total number of contacts in the Sandbox is '
+ total + '\n'
+ modified +' contacts were updated'
;
Messaging.SingleEmailMessage[] messages =   new List<Messaging.SingleEmailMessage> {message};
Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);

if (results[0].success) {
    System.debug('The email was sent successfully.');
    } else {
        System.debug('The email failed to send: ' + results[0].errors[0].message);
    }

}

Please mark this answer as accepted if this helps you. Thanks.

| improve this answer | |
  • thank you for your help. Your suggestion to remove the !Test.isRunningTest() was excellent, code coverage is now 97%. However, I still get a red line on the ProductionException. – Json Dec 14 '16 at 11:37
  • I have updated my answer, please try the updated code – Patlatus Dec 14 '16 at 12:03

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.