+ Start a Discussion
SennahSennah 

Test how many emails have been queued

Hi community,

 

I have coded an email handler that sends out an email to a campaign member when the  CampaignMember gets insert and fulfills certain criteria. That works just fine.

 

My test class inserts a campaign, a lead and a contact and then CampaignMembers  for them. I don't want to call the method directly because I want to test real conditions. That's why my code inserts all the objects and the insert of the CampaignMember fires the trigger that sends out the email.

 

When reviewing the debug log I can verify that the emails have been queued, so the code is working as desired and I have 100% code coverage. Also does my manual test verifies that the code works.

 

But, and here's my question: How can I make sure (assert), that emails have been sent.

I tried 

System.Limits.getEmailInvocations();

 

but that always returns 0.

 

Hope anyone can help with this!

 

Best,

Hannes

 

Best Answer chosen by Admin (Salesforce Developers) 
mtbclimbermtbclimber

So I tested the approach you described and it seems to work for me. My code is included below for your reference. 

 

IMO, however, that the exception approach I described is better for asserting that the email was actually added to the queue functionally because knowing that sendEmail was invoked doesn't mean it was successful whereas the absence of an exception thrown when SendEmailResult.isSuccess() returns false does.

 

public class EmailUtils { public static void SendNotification(String to) { Messaging.SingleEmailMessage m = new Messaging.SingleEmailMessage(); m.toAddresses = new String[]{to}; m.subject = 'This is a notification.'; m.plainTextBody = 'You have been notified.'; Messaging.sendEmail(new Messaging.SingleEmailMessage[]{m}); } static testmethod void testLimitDirect() { EmailUtils.SendNotification('user@email.com'); Integer count = Limits.getEmailInvocations(); System.assertEquals(1,count,'Limits method isnt reflecting the sendemail call that was made in test context.'); } static testmethod void testLimitWithContextSwitch() { Test.startTest(); EmailUtils.SendNotification('user@email.com'); Integer count = Limits.getEmailInvocations(); Test.stopTest(); System.assertEquals(1,count,'Limits method isnt reflecting the sendemail call that was made in runtime context.'); } static testmethod void negativeTestLimitWithContextSwitch() { Test.startTest(); EmailUtils.SendNotification('user@email.com'); Test.stopTest(); Integer count = Limits.getEmailInvocations(); System.assertEquals(0,count,'Limits method is reflecting the sendemail call that was made in runtime context.'); } }

 


 

All Answers

mtbclimbermtbclimber

Right now there is no way to assert against the enqueued email in a request.  We're working on that.

 

I'll look into the limit inspection approach you've described as I don't immediately see why it would report zero after you've invoked a method that calls sendEmail.

 

One thing you might be able to do is check the results of the sendemail call in your runtime code and if it fails throw an exception. Then in your test if no exception is thrown you know it was successful. 

 

Thanks,

mtbclimbermtbclimber

So I tested the approach you described and it seems to work for me. My code is included below for your reference. 

 

IMO, however, that the exception approach I described is better for asserting that the email was actually added to the queue functionally because knowing that sendEmail was invoked doesn't mean it was successful whereas the absence of an exception thrown when SendEmailResult.isSuccess() returns false does.

 

public class EmailUtils { public static void SendNotification(String to) { Messaging.SingleEmailMessage m = new Messaging.SingleEmailMessage(); m.toAddresses = new String[]{to}; m.subject = 'This is a notification.'; m.plainTextBody = 'You have been notified.'; Messaging.sendEmail(new Messaging.SingleEmailMessage[]{m}); } static testmethod void testLimitDirect() { EmailUtils.SendNotification('user@email.com'); Integer count = Limits.getEmailInvocations(); System.assertEquals(1,count,'Limits method isnt reflecting the sendemail call that was made in test context.'); } static testmethod void testLimitWithContextSwitch() { Test.startTest(); EmailUtils.SendNotification('user@email.com'); Integer count = Limits.getEmailInvocations(); Test.stopTest(); System.assertEquals(1,count,'Limits method isnt reflecting the sendemail call that was made in runtime context.'); } static testmethod void negativeTestLimitWithContextSwitch() { Test.startTest(); EmailUtils.SendNotification('user@email.com'); Test.stopTest(); Integer count = Limits.getEmailInvocations(); System.assertEquals(0,count,'Limits method is reflecting the sendemail call that was made in runtime context.'); } }

 


 

This was selected as the best answer
SennahSennah

Great Andrew! Thanks a lot.

Of course, when asserting in the test context it work's.

 

... at least for most tests. I do have a very complex test which sents out mails to leads and contacts for two campaigns. That is 20 leads and 1 contact for each campaign. Total of 42 mails to be sent. The debug log says they are queued but the getEmailInvocations returns only 4:

 

 

19:33:12.226|TOTAL_EMAIL_RECIPIENTS_QUEUED|42 19:33:12.226|STATIC_VARIABLE_LIST CampaignMemberEmailHandler:workList:172 19:33:12.226|CUMULATIVE_LIMIT_USAGE_END 19:33:12.226|CODE_UNIT_FINISHED 19:33:12.229|DML_END|[228,7]| 19:33:12.229|METHOD_ENTRY|[229,7]|System.assertEquals(Integer, Integer) 19:33:12.229|METHOD_ENTRY|[229,31]|Limits.getEmailInvocations() 19:33:12.229|METHOD_EXIT|[229,31]|getEmailInvocations() 19:33:12.229|EXCEPTION_THROWN|[229,7]|System.Exception: Assertion Failed: Expected: 42, Actual: 4 19:33:12.229|METHOD_EXIT|[229,7]|assertEquals(ANY, ANY) 19:33:12.229|FATAL_ERROR|System.Exception: Assertion Failed: Expected: 42, Actual: 4

 

 Any idea what that could be?

I will also give my code a review.

 

However, I will also follow your advise and build a try block around the email invocation.

 

Best,

Hannes

 

mtbclimbermtbclimber

Great. 

 

By the way, the limit tracks the number of times the sendEmail() method is invoked - not how many emails you are sending out. So if your 42 emails are delivered by invoking sendEmail() 4 times, as might be the case if you are calling it once per campaign for each type of recipient (Lead/Contact), that would explain the discrepancy.

 

 

Message Edited by mtbclimber on 02-19-2010 10:38 PM
SennahSennah

Yes, that is indeed the case. I determine how many recipients and then based on that make either a single or mass mailing.

 

So do I get you right that I will have to wait 'till the feature request has been implemented to test this case properly?

mtbclimbermtbclimber

Not exactly. You can write code that can be tested and asserted using the approach described above. The only thing is you have to code your runtime in a manner that is specific so it can be tested.

 

The feature will make it so you really don't have to code the runtime a specific way.  You shouldn't have to do that nor should you have to spend your code writing effort, statement execution, etc. to workaround this, but that doesn't prevent you from having sufficient automation here unless there is something I've missed.

 

Thanks for your patience.