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.
No comments:
Post a comment