0

I currently have a Batchable process that will send emails to some users:

global class ExpiryNotificationHandler implements Database.Batchable<sObject> {
    global System.Iterable<sObject> start(Database.BatchableContext context) {
        return [SELECT Id, Email, Name FROM User WHERE UserRole.Name = 'Regional Manager'];
    }

    global void execute(Database.BatchableContext context, List<User> users) {
        EmailTemplate emailTemplate = [SELECT Id FROM EmailTemplate WHERE DeveloperName = 'Expiry_Notification' LIMIT 1];
        for (User u: users) {
            Messaging.SingleEmailMessage email = Messaging.renderStoredEmailTemplate(emailTemplate.Id, UserInfo.getUserId(), u.Id);
            email.setSaveAsActivity(false);
            email.setToAddresses(new List<String> { u.Email });

            Messaging.SendEmailResult[] mailResult = Messaging.sendEmail(new List<Messaging.Email> { email });
        }
    }

    global void finish(Database.BatchableContext context) {
        // Call another process
    }
}

The email grabs some extra data and prints it in a table in the email.

I can create a unit test what will create the required data for the process to run, the problem is that the unit test fails at Messaging.renderStoredEmailTemplate() with the error:

System.EmailTemplateRenderException: EMAIL_TEMPLATE_MERGEFIELD_ERROR: List has no rows for assignment to SObject

My suspicion is that even though I have created the correct data for the unit test, when it is trying to render the email, it is not running in the same context as the unit test. Thus it can't see any of the test data that I have created.

One way that I can work around this is that I can annotate my test method with SeeAllData = true but given that my org might not have the data that is needed for the process/email (I am currently testing this in my dev org), I don't think the is the best solution.

Is there a way that I can create test data in a unit test and make it visible to when the visualforce email template when running a unit test?

I have tried using the Messaging.renderStoredEmailTemplate() function as well as configuring the Messaging.SingleEmailMessage() object:

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTemplateId(emailTemplate.Id);
mail.setWhatId(u.Id);
mail.setTargetObjectId(UserInfo.getUserId());
mail.setSaveAsActivity(false);
mail.setToAddresses(new List<String> { u.Email });
  • 1
    it would help if you can show test class also – salesforce-sas Jul 28 at 4:57
0

Signature of renderStoredEmailTemplate is renderStoredEmailTemplate(templateId, whoId, whatId). The 2nd parameter should be lead, contact or user Id and 3rd parameter can be any other object (like account or opportunity). This could be the possible reason.

I believe, you are trying to send an email to each user retrieved from start method, so targetObjectId should be that user so that merge fields can be properly set. And whatId should be one of Account, Asset, Campaign, Case, Contract, Opportunity, Order, Product, Solution, Custom. It makes more sense of setting whatId if the targetObjectId/whoId is contact.

Try this:

global System.Iterable<sObject> start(Database.BatchableContext context) {
    return [SELECT Id, Email, Name FROM User WHERE UserRole.Name = 'Regional Manager'];
}

global void execute(Database.BatchableContext context, List<User> users) {
    EmailTemplate emailTemplate = [SELECT Id FROM EmailTemplate WHERE DeveloperName = 'Expiry_Notification' LIMIT 1];
    Messaging.SingleEmailMessage[] messages =   new List<Messaging.SingleEmailMessage>();
    for (User u: users) {
        Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
        email.setTemplateId(emailTemplate.Id);
        email.setTargetObjectId(u.Id);
        email.setSaveAsActivity(false);
        email.setToAddresses(new List<String> { u.Email });
        messages.add(email);
    }
    Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
}

global void finish(Database.BatchableContext context) {
    //
}

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.