Monthly Archives: September 2014

Versioning woes – ApexPages.addMessage

I recently updated my Util class from V26 to V31. Unfortunately, this broke some VF page test methods. After some experimentation, I traced the problem down to this:

The ApexPages.addMessage() method has several instantiation forms. The one I was using is:

public Message(ApexPages.Severity severity, String summary, String detail)

Using a pattern like this in some of my VF controllers that did some substantial DML:

public PageReference fooActionMeth() {
  String step;
  try {
    step = '01 step';
    // do some work 'A' using various Util methods that can throw exceptions
    // do some other work 'B' using various Util methods that can throw exceptions
    step = '02 step';
    // do some more work using various Util methods that can throw exceptions
  }
  catch (exception e) {
   ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,
                                              'some error at step:'+step,
                                              e.getMessage()));
  }
}

My testmethod was structured as shown below. I like this pattern because I can test all the error conditions (usually) in sequence within one testmethod rather than going through the overhead of multiple testmethods, one per error case.

 // ...
 Test.startTest();
 Test.setCurrentPage(Foo.page);
 PageReference resPg;
 // set up conditions to test step 1 and verify exception for work 'A' occurs
 resPg = fooAction();
 System.assert(getMostRecentMsg().contains('expected error code'));
 // set up conditions to test step 1 and verify exception for work 'B' occurs
 resPg = fooAction();
 System.assert(getMostRecentMsg().contains('expected error code')); // fails at V31
 // set up conditions to test step 2 and verify exception occurs
 resPg = fooAction();
 System.assert(getMostRecentMsg().contains('expected error code'));
  // ...
 
  // utility method
  private static String getMostRecentMsg() {
     return ApexPages.hasMessages() 
	? ApexPages.getMessages()[ApexPages.getMessages().size()-1].getSummary() + 
          ' ' + 
          ApexPages.getMessages()[ApexPages.getMessages().size()-1].getDetail() 
	: null;
   }

But, when I upgraded the version of the Util worker code to V31 from V26, the testmethod stopped working for the second assert. Why?

To resolve, I broke the problem down to its essential elements using a separate test class:

@isTest
private static void testAddVFMsg() {    
    Test.startTest();
    Test.setCurrentPage(Page.Foo);
    ApexPages.addMessage(
      new ApexPages.Message(ApexPages.Severity.INFO,'MsgSummary','00detail'));
    System.assertEquals(1,ApexPages.getMessages().size());

    ApexPages.addMessage(
      new ApexPages.Message(ApexPages.Severity.INFO,'MsgSummary','01detail'));
     // passes at V28 and earlier, fails at V29+
    System.assertEquals(2,ApexPages.getMessages().size()); 

    Test.stopTest();
}

Note the arguments to the ApexPages.Message constructor between the two calls. Same summary (second argument), different detail (third argument). I then tried it at V31, V30, …until it passed.

Conclusion
ApexPages.addMessage() behavior varies by SFDC version if the i+1st message has the same summary as the ith message, even if the detail argument is different between i+1st and ith message.

If the summary values are the same, the i+1st message won’t get added to the page messages. This change happened as of V29.

Seems to me that if you call addMessage(..), the resulting getMessages() should include the message you added