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?


public class unsubscribe_user {
    public String email {
    public String token {

    public unsubscribe_user() {}

    public PageReference unsubscribeMe() {
        try {
            List<Contact> contactList = [
                select Name,
                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:

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';
        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;

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

        // 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);



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;        


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...')));
  • You've tested only if I recieve a message but not the contents, is there any reason for this? – Deployment Failure Jan 26 '15 at 12:35
  • I've left that as something for you to implement. You should replace the comment with some code that will check the content of the messages. I'll add an example. – Alex Tennant Jan 26 '15 at 13:18
  • Looking at my addMessage line: ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Warning, 'You are not in our mailing list (you may have already been removed)')); does the message fall under getSummary or getDetail? – Deployment Failure Jan 26 '15 at 14:29
  • 1
    Alex - I use a variant of this by always prefixing my messages with [nnn] where nnn is class/message-specific - this way I can verify message presence without having to worry about exact match on message text which is prone to change with better grammar, more hints to the end user, etc. – cropredy Jan 26 '15 at 20:49
  • 1
    @crop1645 I store all of my messages in Custom Labels to mitigate that. Then you're just comparing that the correct label has been used and don't care about the content. – Alex Tennant Jan 26 '15 at 22:30

Try something like this:

PageReference pageRef = Page.unsubscribePage; //new page reference
pageRef.getParameters().put('x', 'y');        //set additional paramethers
Test.setCurrentPage(pageRef);                 // set as current page

// your test logic

List<Apexpages.Message> pageMessages = ApexPages.getMessages();
  • Where would this go in the context of my own test, would I not call the controller to test the actual method? – Deployment Failure Jan 26 '15 at 12:30
  • You should set page before creating new instance of controller and get list of messages after calling methods from controller – Artur Kępczyński Jan 26 '15 at 12:39

After summer 18 you can now clear your messages in apex tests, no more static variables needed: https://releasenotes.docs.salesforce.com/en-us/summer18/release-notes/rn_apex_clear_page_messages.htm

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.