[SalesForce] How to test page messages in unit test

I have an Apex controller which unsubscirbes users from email via an opt-out form. I have written a test class which tests the method (or atleast partially at the moment). I would like to know how I could test returned page messages and also negative testing (where the user is already unsubscribed, could I simply creata a new instance of the PageReference and controller?

Controller:

public class unsubscribe_user {
    public String email {
        get;
        set;
    }
    public String token {
        get;
        set;
    }

    public unsubscribe_user() {}

    public PageReference unsubscribeMe() {
        try {
            List<Contact> contactList = [
                select Name,
                    Email,
                    HasOptedOutOfEmail
                from Contact
                where Email = :email and
                    Id = :token.substring(10) and
                    hasOptedOutOfEmail = false
                limit 100
            ];

            if (contactList.isEmpty()) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Warning, 'You are not in our mailing list (you may have already been removed)'));
                return null;
            }

            for (Contact contact: contactList) {
                contact.hasOptedOutOfEmail = true;
            }    

            update contactList;
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Info, 'You have been successfully removed from our mailing list'));
        } catch (System.QueryException e) {
            System.debug(System.LoggingLevel.ERROR, 'Contact Query Issue: ' + e.getMessage());
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Fatal, 'FATAL Error: Please contact the administrator'));
        }   

        return null;
    }
}

Test Class:

@isTest
private class rsvp_user_test {

    static testMethod void unsubscribeMe_test() {

        Account acc = new Account();
        acc.Name =  'TestAccount';
        acc.Airport__c = 'LHR';
        acc.Industry = 'Airline';
        acc.LHR__c = true;
        acc.AcctExtID__c = '123';
        acc.Customer_Account_number__c = '112233';
        acc.Compare_Customer_Accont_Number__c=112233;
        insert acc;

        Contact co = new Contact();
        co.AccountId = acc.Id;
        co.Email = 'johndoe_test@mail.com';
        co.LastName = 'CONTACT';
        co.Airport__c = 'LHR';
        insert co;

        PageReference pg = Page.Snsubscribe;
        Test.setCurrentPage(pg);

        unsubscribeMe controller = new unsubscribeMe();
        // Act
        controller.email = co.Email;
        controller.unsubscribeMe();

        // Assert
        Contact insertedData = [SELECT Id, Email, HasOptedOutOfEmail FROM Contact WHERE Email = :co.Email];
        System.assertEquals(insertedData.hasOptedOutOfEmail, true);

        // test again
        // System.assertEquals(insertedData.hasOptedOutOfEmail, co.Id);


    }

}

Best Answer

You can use ApexPages.getMessages() within your test to get the page messages for the current context, then check that array to make sure that it contains the error message that you're expecting.

ApexPages.Message[] pageMessages = ApexPages.getMessages();
System.assertNotEquals(0, pageMessages.size());

// Check that the error message you are expecting is in pageMessages
Boolean messageFound = false;

for(ApexPages.Message message : pageMessages) {
    if(message.getSummary() == 'Your summary'
        && message.getDetail() == 'Your detail'
        && message.getSeverity() == ApexPages.Severity.YOUR_SEVERITY) {
        messageFound = true;        
    }
}

System.assert(messageFound);

This is the pattern I tend to use, even for single messages, as it can easily be adapted to check for multiple messages whilst not caring about what order they are added to the page.

Alternatively you can factor it out into a helper method:

private static Boolean wasMessageAdded(ApexPages.Message message) {
      Boolean messageFound = false;

     for(ApexPages.Message msg : pageMessages) {
         if(msg.getSummary() == message.getSummary()
             && msg.getDetail() == message.getDetail()
             && msg.getSeverity() == message.getSeverity()) {
             messageFound = true;        
         }
     }

     return messageFound;
}

Then use it as follows:

System.assert(wasMessageAdded(new ApexPages.Message('Your validation message here...')));
Related Topic