Blog

Here's what's on the minds of our marketing and technology experts.

For more perspectives from Sundog, check out Sundog: The Podcast and our knowledge.

RSS Icon Subscribe to blog feed What's this?

Paul Bourdeaux
.(JavaScript must be enabled to view this email address)
Senior Software Engineer

Presents insights, trends and recommendations for using mobile technologies.

More posts by this author

Full Post

Testing Asynchronous Methods in the Cloud

One of the relatively recent additions to the Force.com platform was the ability to make calls to asynchronous methods from Apex classes.  By using the @future (callout=true) annotation, we can set up the method to be called in a seperate, asynchronous request.  This gave the developers the ability to run logic outside the current transaction, create asynchronous data loads, etc.  But it also presented one obstacle… The method could only be called asynchronously.  Which made testing a problem.

Take the following code snippet for example.  It simply deletes Lead objects in the database (not a very practical example, but hey - it is just an example!).
01       @future (callout=true)
02       public static void deleteLeads(List leadIds) {
03              String queryString = ‘SELECT Name from Lead where ‘;
04              Integer numIds = 1;
05              for (String id: leadIds) {
06                     if (numIds > 1) {
07                            queryString = queryString + ‘ OR ‘;
08                     }
09                     numIds = numIds + 1;
10                     queryString = queryString + ‘ID=’’ + id + ‘’’;
11              }
12              
13              List leadsToDelete = Database.query(queryString);              
14              delete leadsToDelete;
15       }

At first glance, testing looks like it would be easy enough.  Simply identify the objects you want to perform the logic on, call the method, and then test to see if the logic was run on the objects.  Right?
01       static testMethod void testDeleteLeads() {
02              
03              String uniqueLastName = ‘TEST’ + System.now();
04              Lead duplead = new Lead();
05              duplead.company= ‘test’;
06              duplead.lastname = uniqueLastName ;
07              insert duplead;       
08              
09              Lead duplead2 = new Lead();
10              duplead2.company= ‘test2’;
11              duplead2.lastname = uniqueLastName ;              
12              insert duplead2;
13              
14              List duplist = [SELECT name from Lead where lastname=:uniqueLastName ];
15              
16              List duplicateLeadIds = new List();
17              duplicateLeadIds.add(’’ + duplist.get(0).id);
18              duplicateLeadIds.add(’’ + duplist.get(1).id);
19              
20              deleteLeads(duplicateLeadIds);
21
22              List duplist2 = [SELECT name from Lead where lastname=’test’];
23              System.assert(duplist2.size()==0);
24       }

Unfortunately, this test fails every time.  Why?  because the deleteLeads method is not called in the same request - meaning that when the logic to delete the Leads has not been run when the assert takes place.  So how do we test this?  The solution is kind of hacky, but it works well.  Simply move all of the logic out of the asynchronous method and into a normal method that the asynchronous method calls.

01       @future (callout=true)
02       public static void deleteLeads(List leadIds) {
03              deleteLeads_nonAsynch(leadIds);
04       }
05
06       public static void deleteLeads_nonAsynch(List leadIds) {
07              String queryString = ‘SELECT Name from Lead where ‘;
08              Integer numIds = 1;
09              for (String id: leadIds) {
10                     if (numIds > 1) {
              ...

While the deleteLeads method is still untestable, the deleteLeads_nonAsynch can easily be tested by changing line 20 in the test method to read:
20              deleteLeads_nonAsynch(duplicateLeadIds);

We now have a high degree of test coverage, and are accurately testing the function of the code itself.  Is it pretty?  Nope.  But it works.

Don't miss any posts! Subscribe to our blog feed or only posts by Paul Bourdeaux.

Short URL: http://sundoginteractive.com/e/3106

Comments

Be the first to comment!

Leave A Comment

Please help us stop spam by typing the word you see in the image below:

Contact Us

Fill out and send the form below to learn about our refreshing approach to measureable marketing, or call 1.888.9.sundog.

     
Follow us on:
Twitter
Facebook
Flickr
Google+