Blog

Monday, 28 May 2012

Mock FacesContext in Arquillian

Recently I wanted to test my backing beans for JSF views. Unfortunately the EntityQuery (from seam3-persistence-framework) is very tightly bound to JSF api, particularly it depends on FacesContext.getCurrentInstance().getELContext(). The problem is that the tests are not associated with JSF requests, so FacesContext.getCurrentInstance() returns null.

I decided to extend mock-contexts-extension to help mocking FacesContext.
Let's say that we want to test if our component for retrieving list of objects from database returns good results. The component extends class pl.com.it_crowd.seam.framework.EntityQuery which in turn extends pl.com.it_crowd.seam.framework.Query. Our component uses such EJBQL:
"select u from User u where u.company=#{currentUser.company}". Our EntityQuery will parse it and try to create ValueExpression,

    private List<Object> getParameterValues(List<ValueExpression> valueBindings)
    {
        List<Object> values = new ArrayList<Object>(valueBindings.size());
        for (int i = 0; i < valueBindings.size(); i++) {
            values.add(valueBindings.get(i).getValue(facesContext.get().getELContext()));
        }
        return values;
    }
As you can see it needs to get ELContext and it takes it from injected facesFontext instance. The problem is that call to facesContext.get() will result in exception, because FacesContext instance producer checks if FacessContext.getCurrentInstance returns null.
Setting FacesContext in regular way requires too many dependencies (ServletContext,ServletRequest,ServletResponse,Lifecycle) that I decided it's better to use mock. Especially that I need to mock only one method: getELContext().

Here is the solution: x
@RunWith(Arquillian.class)
public class UserListCIT {

    @Inject
    private CommonCITSteps commonCITSteps;

    @Inject
    private UserList userList;

    @SuppressWarnings("CdiInjectionPointsInspection")
    @Inject
    private ELContext elContext;

    @Inject
    private Identity identity;

    @Deployment
    public static WebArchive createDeployment()
    {
        //...standard archive building
    }

    @FacesContextRequired
    @ConversationScopeRequired
    @Test
    public void attemptToAccessOtherCompanyData()
    {
        Assert.assertFalse(identity.isLoggedIn());
        commonCITSteps.login("jack", "aaaaa");
        Assert.assertTrue(identity.isLoggedIn());
        Assert.assertTrue(userList.getResultList().isEmpty());
    }

    @MockFacesContextProducer
    public FacesContext mockFacesContext()
    {
        FacesContext mock = mock(FacesContext.class);
        when(mock.getELContext()).thenReturn(elContext);
        return mock;
    }
}
I annotate test method with @FacesContextRequired, which tells our mock-contexts-extension that test depends on FacesContext and the test provides mock for this. Also test class has method annotated with @MockFacesContextProducer which should return FacesContext. I use Mockito to create mock that returns elContext which is injected component, produced by seam solder.

If 2 different tests would need different mocks then both annotations FacesContextRequired and MockFacesContextProducer have "name" attribute which can be used to identify the right mock.

Read this article to learn about mock-contexts-extension.

1 comment:

  1. We accurately guessed that the subsequent card could be purple so we at the moment are|are actually} introduced with the choices to gather or to Gamble again for the prospect to win 40 coins. Super Times Pay – The participant has the option to play a sixth coin. When they accomplish that randomly selected sport rounds could have a 2×, 3×, 4×, 5×, 8× or 10× multiplier utilized to any win. In the instance under you can to|you probably can} see a 10 hand https://thekingofdealer.com/jumbo-casino/ sport where the participant has been dealt 2 Pairs alongside the two of hearts. Before you throw down your hard-earned money in a on line casino, PRACTICE FIRST!

    ReplyDelete