Sunday, 21 August 2011

Writing unit tests for the PageReference Class

Before you can deploy any Salesforce project to production, unit tests have to be written that ensure that future releases or platform upgrades do not cause any element of your system to malfunction. When writing tests for Apex controller classes, it is likely that you will have to write test methods that relate to action methods. Action methods in controllers have to return a Page Reference, which can be used to direct the user to another page as soon as the action completes. Parameters and other variables can also be added to the page references.

To achieve a suitable level of coverage and fault tolerance, your test methods should ensure that calling an action returns the correct page reference. It sounds simple enough, but testing these page references is not as straightforward as you might think. Take the following example of a simple controller method and an accompanying test method.

public class PageReferenceTestingController{

  PageReference changeThePageAction(){
    
   // Action code HERE

    return Page.SomeOtherPage;
  }
  
  static testmethod void testChangeThePageAction(){
  
    PageReferenceTestingController testPRTC = 
      new PageReferenceTestingController();
  
    system.assertEquals(Page.SomeOtherPage, 
                        testPRTC.changeThePageAction());
  }
}

Looks simple enough, but when we execute the test methods through the Salesforce interface, we retrieve the following error message:


Not really the most helpful message in the world, as the two are seemingly identical :) .

 The simplest way to avoid this problem is to simply compare the URL attributes of the page references, like so:

public class PageReferenceTestingController{

  PageReference changeThePageAction(){
  
    // Action code HERE
  
    return Page.SomeOtherPage;
  }
  
  static testmethod void testChangeThePageAction(){
  
    PageReferenceTestingController testPRTC = 
      new PageReferenceTestingController();
  
    system.assertEquals(Page.SomeOtherPage.getURL(), 
                        testPRTC.changeThePageAction().getURL());
  }
}

If we run the test methods for this class again, it successfully passes.

BUT......... we are only testing the URL of the redirected page, what if we have added parameters we want to check? Wouldn't it be better to test the whole object?

 The way to best achieve this is to write a static page reference comparison method. This will iterate through the different page reference attributes and compare them one by one. This will allow you to easily compare two page references quickly and effectively. See the following example.

ublic class PageReferenceTestingController{

  PageReference changeThePageAction(){
  
    // Action code HERE
  
    PageReference goToSomeOtherPage = Page.SomeOtherPage;
    
    goToSomeOtherPage.setRedirect(false);
    goToSomeOtherPage.getParameters().put('a','b');
    goToSomeOtherPage.getParameters().put('c','d');
    goToSomeOtherPage.getParameters().put('e','f');
  
    return goToSomeOtherPage;
  }
  
  static testmethod void testChangeThePageAction(){
  
    PageReferenceTestingController testPRTC = 
      new PageReferenceTestingController();
  
    PageReference testPageReference = Page.SomeOtherPage;
    
    testPageReference.setRedirect(false);
    testPageReference.getParameters().put('e','f');
    testPageReference.getParameters().put('a','b');
    testPageReference.getParameters().put('c','d');
  
    system.assert(arePageReferencesEqual(testPageReference, 
                                         testPRTC.changeThePageAction()));
  }
  
  static Boolean arePageReferencesEqual(PageReference page1, 
                                        PageReference page2){
  
    // First do a null test.
    if (page1 == null && page2 == null) return true;
    if (page1 == null && page2 != null) return false;
    if (page1 != null && page2 == null) return false;   
  
    // If none of the page references are null, compare their attributes.
    if (page1.getAnchor()     == page2.getAnchor()
     && page1.getURL()        == page2.getURL()
     && page1.getRedirect()   == page2.getRedirect()
     && page1.getCookies()    == page2.getCookies()
     && page1.getHeaders()    == page2.getHeaders()
     && page1.getParameters() == page2.getParameters()){
     
       return true;
    }   
      
    return false; 
  }
}