8

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 = '[email protected]';
        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);


    }

}

3 Answers 3

12

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...')));
7
  • You've tested only if I recieve a message but not the contents, is there any reason for this? Commented Jan 26, 2015 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. Commented Jan 26, 2015 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? Commented Jan 26, 2015 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
    Commented Jan 26, 2015 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. Commented Jan 26, 2015 at 22:30
2

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();
2
  • Where would this go in the context of my own test, would I not call the controller to test the actual method? Commented Jan 26, 2015 at 12:30
  • You should set page before creating new instance of controller and get list of messages after calling methods from controller Commented Jan 26, 2015 at 12:39
1

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .