I have some code in an After Insert trigger that does some conditional DML updates to the records being inserted if a mail is successfully sent out. I'm looking for a solid, modular way to test this, however I'm not confident my strategy is sound, so perhaps someone can set me straight?
First here's the section of code in the trigger that is handling the Messaging service and updating the records:
@testVisible static IMessagingService messagingService;
public static void mailOutSalesOrderContract(List<signature__Signature__c> signatureList) {
// Aggregate mails here
messagingService = new MessagingService();
List<Messaging.SendEmailResult> sendEmailResults = new
List<Messaging.SendEmailResult>();
sendEmailResults = messagingService.sendEmail(mails, false);
if (sendEmailResults != null) {
// Mails are sent out in the order they are added to the mails list.
// And they are added to the mails list in the order they come in
// via the mailOutSalesOrderContract signatureList parameter.
// Knowing this we can update the correct signature record and
// mark that it has been sent.
Integer i=0;
List<signature__Signature__c> updatedSignatures = new List<signature__Signature__c>();
signature__Signature__c updatedSignature = new signature__Signature__c();
for(Messaging.SendEmailResult sendEmailResult : sendEmailResults){
if (sendEmailResult.isSuccess()) {
updatedSignature = new signature__Signature__c(Id=signatureList[i].Id);
updatedSignature.signature__Emailed__c = DateTime.now();
updatedSignature.signature__Status__c = 'Emailed';
}
else {
for (Messaging.Sendemailerror sendEmailError : sendEmailResult.getErrors()){
updatedSignature = new signature__Signature__c(Id = signatureList[i].Id);
updatedSignature.signature__Emailed__c = DateTime.now();
updatedSignature.signature__Status__c = 'Failed';
updatedSignature.Comments__c = 'Send Email Result Error: ' + sendEmailError.Message;
}
}
updatedSignatures.add(updatedSignature);
i++;
}
update updatedSignatures;
}
}
I've abstracted the messaging into an interface for more modularity as follows (alot of this is taken from this post https://salesforce.stackexchange.com/a/73316/26381
public class MessagingService implements IMessagingService {
public Messaging.SendEmailResult[] sendEmail(Messaging.Email[] emails, Boolean allOrNothing) {
if (!Test.isRunningTest()) {
// If we aren't in a test, run Messaging.sendEmail normally
// passing results back to our implemenation.
return Messaging.sendEmail(emails, allOrNothing);
}
else {
System.Debug('!!! MessagingService called inside a test. Consider using a mock of IMessagingService.');
return null;
}
}
}
I'm thinking my strategy is to conditionally implement a mock version of IMessagingService and utilize it something like this?:
public class MessagingService implements IMessagingService {
public Messaging.SendEmailResult[] sendEmail(Messaging.Email[] emails, Boolean allOrNothing) {
if (!Test.isRunningTest()) {
// If we aren't in a test, run Messaging.sendEmail normally
// passing results back to our implemenation.
return Messaging.sendEmail(emails, allOrNothing);
}
else {
IMessagingService messagingServiceMock = new MessagingServiceMock();
return messagingServiceMock.sendEmail(emails, allOrNothing);
}
}
}
Something seems fishy with this strategy though...