Search code examples
javajsfjsf-2juniteasymock

JSF - JUnit FacesContext mock Test


I have some problem with wirint testcase for my JSF app. So i want to test my logout method:

            FacesContext context = EasyMock.createMock(FacesContext.class);
            String userName = "testUserName";
            HttpSession session = EasyMock.createMock(HttpSession.class);
            ExternalContext ext = EasyMock.createMock(ExternalContext.class);
            EasyMock.expect(ext.getSession(true)).andReturn(session);
            EasyMock.expect(context.getExternalContext()).andReturn(ext).times(2);
            context.getExternalContext().invalidateSession();
            EasyMock.expectLastCall().once();           

            EasyMock.replay(context);
            EasyMock.replay(ext);
            EasyMock.replay(session);

            loginForm = new LoginForm();
            loginForm.setUserName(userName);
            String expected = "login";
            String actual = loginForm.logout();
            context.release();

            Assert.assertEquals(expected, actual);
            EasyMock.verify(context);
            EasyMock.verify(ext);
            EasyMock.verify(session);

My logout method is:

    public String logout() {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "/authentication/login.xhtml?faces-redirect=true";
    }

My problem is that i got a nullpointer exception here: EasyMock.expectLastCall().once() How should it be properly tested? I guess it is something with the mocks but i couldnt find a solution, how could i mock properly the FacesContext in this case


Solution

  • In order to make the above work you could use for example PowerMock which is a framework that allows you to extend mock libraries like EasyMock with extra capabilities. In this case it allows you to mock the static methods of FacesContext.

    If you are using Maven, use following link to check the needed dependency setup.

    Annotate your JUnit test class using these two annotations. The first annotation tells JUnit to run the test using PowerMockRunner. The second annotation tells PowerMock to prepare to mock the FacesContext class.

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ FacesContext.class })
    public class LoginFormTest {
    

    Now go ahead and mock FacesContext using PowerMock like you would do for the other classes. Only difference is that this time you perform replay() and verify() on the class not the instance.

    @Test
    public void testLogout() {
    
        // mock all static methods of FacesContext
        PowerMock.mockStatic(FacesContext.class);
    
        FacesContext context = EasyMock.createMock(FacesContext.class);
        ExternalContext ext = EasyMock.createMock(ExternalContext.class);
    
        EasyMock.expect(FacesContext.getCurrentInstance()).andReturn(context);
        EasyMock.expect(context.getExternalContext()).andReturn(ext);
    
        ext.invalidateSession();
        // expect the call to the invalidateSession() method
        EasyMock.expectLastCall();
        context.release();
    
        // replay the class (not the instance)
        PowerMock.replay(FacesContext.class);
        EasyMock.replay(context);
        EasyMock.replay(ext);
    
        String userName = "testUserName";
        LoginForm loginForm = new LoginForm();
        loginForm.setUserName(userName);
    
        String expected = "/authentication/login.xhtml?faces-redirect=true";
        String actual = loginForm.logout();
        context.release();
    
        Assert.assertEquals(expected, actual);
    
        // verify the class (not the instance)
        PowerMock.verify(FacesContext.class);
        EasyMock.verify(context);
        EasyMock.verify(ext);
    }
    

    I've created a blog post which explains the above code sample in more detail.