Recently I experienced some problems trying to test the page messages that were being added to a Visualforce page by subsequent controller calls. As this behaviour is a bit specific, I will try to explain how it works with examples.
For the example, we have a simple Visualforce page and a controller:
In these tests I am going to use pageMessages tag. If you want to know more about the different options for showing messages in a Visualforce page, take a look at this great post from Jesse Altman.
As you see in the controller, methods addMessage1() and addMessage2() simply add messages to the page. Method addMessage3AndClear() adds a message and tries to clear it after, and addMessage4AndReload() method adds a message and then performs a page reload. All these methods will be used later.
First we will try a simple test, adding ‘Message 1’ and, after that, adding ‘Message 2’. If we perform this test manually, pressing addMessage1 and addMessage2 buttons, when we press addMessage1, the first message will be added to the page:
And when we press addMessage2, the first one will be deleted, and the second one added:
If we write a unit test to check this, however, both messages will be added to PageMessages variable, as the context is not refreshed between the two requests inside a unit test. This test, which proves this fact, will pass:
What can we do to refresh PageMessages variable in my tests? Let’s try recreating the controller:
The test passes again. Recreating the controller doesn’t reset PageMessages.
Let’s try now to clear PageMessages after adding ‘Message 3’. Then no messages should appear, right? If we click addMessage3AndClear button, this is the result:
This is, ApexPages.getMessages().clear() won’t have any effect outside test context. If we write a unit test, the result will be the same, no effect from the clear() method inside a unit test:
Let’s try then forcing a page reload. Supposedly, a page reload will flush everything in the viewstate. If we click addMessage4AndReload manually, it works, ‘Message 4’ is added but then deleted when reloading the page.
Then, great! A page reload does reset PageMessages outside test context. If we write a unit test that simulates this call:
The test passes again, this is, the PageMessages is not emptied when performing a page reload inside a test method.
So, after further investigations we find there is no way of clearing PageMessages inside a test method. In contrast, any real server request will clear PageMessages, as the context changes and the PageMessages variable is initialized. There is an idea for changing this behaviour that you can vote.
I want to point out another particular behaviour of PageMessages in test context. What do you think it should happen if we call addMessage1(), after that addMessage2(), and after that addMessage1() again? Should PageMessages contain the three messages?
And the answer is no. The test passes again. This means if we try to add a message to the PageMessages variable which was already contained inside it, it won’t be added again. This is, PageMessages variable acts as a Set, it will not contain duplicate messages.