Testing emails involves many things
- To test that the properties of an email are properly set and that your code actually tries to send an email, see this Stackexchange answer that exploits ApexMocks.
- To test that an email template is properly rendered before sending it, the savepoint - rollback hack is no longer required. You can use built-in Apex methods that render an email template. These are described in this stackexchange answer
The latter use case will mean you should create a wrapper method around your rendering of the template so you can unit test that method in a testmethod by passing in different arguments and verifying the proper application of merge fields to the template
For example
public Messaging.SingleEmailMessage render(ID templateId, ID whoId, ID whatId) {
return Messaging.renderStoredEmailTemplate(templateId, whoId, whatId);
}
and the testmethod
// Given Sobjects corresponding to the whoId and whatId. Mock or fetch an email template and note the Id
Account a = new Account(...);
insert a;
Contact c = new Contact(...);
insert c;
EmailTemplate et;
System.runAs([select Id from User where Id = :Userinfo.getUserId() limit 1][0]) { // creating setup objects requires diff context
Folder[] folders = [select Id from Folder
where AccessType IN: new list<String>{'Shared','Public'}
AND Type = 'Email'];
System.assert(!folders.isEmpty(),'test can\'t run wo Email Template folders. Folders can\'t be mocked in Apex');
// Given an EmailTemplate with merge fields
et = new EmailTemplate( Name = 'TestEmailTemplate ApexTestMethod',
Body = someBodyWithMergeFields,
DeveloperName = 'TestEmailTemplate_ApexTestMethod',
FolderId = folders[0].Id,
HtmlValue =someBodyWithMergeFields,
IsActive = true,
TemplateType = 'custom');
insert et;
}
// When rendering...
Messaging.SingleEmailMessage res = new myClass().render(et.Id, c.id, a.Id);
// Then verify rendered template
System.assertEquals(someExpectedRenderedTemplate,res.getHtmlBody());
Note that you can't use mocked SObjects in memory here to test the above because the code under test actually queries the database given the Ids passed.