Search code examples
javajsfjunitmockingjmockit

Jmockit mock addMessage method from FacesContext


I'm writing component tests for my bean and I'm constantly getting NullPointerExceptions because of the addMessage() method from FacesContext.

I'm sure it's because of the addMessage() method, because if I delete the line the test passes. How do I mock the addMessage() method?

TrendBean

@Named(value = "trendBean")
@ViewScoped
@SuppressWarnings("deprecation")
public class TrendBean extends AbstractBean implements Serializable {

private static final long serialVersionUID = -310401000218411384L;

private static final Logger logger = Logger.getLogger(TrendBean.class);

private ChartPoint point;

private List<ChartPoint> points;

@Inject
private ITrendManager manager;


public String addChartPoint() {
     if (!isLoggedIn()) {
        return null;
     }
     assertNotNull(point);
     final User user = getSession().getUser();
     manager.addPointToUser(user, point);
     FacesContext.getCurrentInstance().addMessage(
            null,
            new FacesMessage(FacesMessage.SEVERITY_INFO,
                getTranslation("pointAdded"), ""));
     init();
     return null;
     }
 }

TrendBeanTest

public class TrendBeanTest {

@Tested
TrendBean trendBean;
@Injectable
LoginBean loginBean;
@Injectable
Session session;
@Injectable
ITrendManager manager;
@Injectable
IUserManager userManager;
@Injectable
User user;

@Test
public void testAddChartPoint(@Mocked FacesContext fakeContext) {

    new NonStrictExpectations() {

        {
            session.isLoggedIn();
            result = true;
            session.getUser();
            result = user;
            manager.addPointToUser((User) any, (ChartPoint) any);
            FacesContext.getInstance();
            result = fakeContext;
        };
    };

    Deencapsulation.setField(trendBean, "point", new ChartPoint());

    assertEquals(null, trendBean.addChartPoint());

    }
}

AbstractBean

public abstract class AbstractBean {

private static final Logger logger = Logger.getLogger(AbstractBean.class);

@Inject
private Session session;


public boolean isLoggedIn() {
    return session.isLoggedIn();
}

protected Session getSession() {
    return session;
}

public String getTranslation(final String messageKey,
        final Object... formatParameters) {
    return getTranslation(getLanguage(), assertNotNull(messageKey),
            assertWithoutNull(formatParameters));
}

 public static String getTranslation(final Locale locale, final String messageKey,
        final Object... formatParameters) {
    try {
        final ResourceBundle bundle = ResourceBundle.getBundle(
                "internationalization.messages", assertNotNull(locale));
        return getTranslation(bundle, assertNotNull(messageKey),
                assertNotNull(formatParameters));
    } catch (final MissingResourceException e) {
        assertNotNull(logger)
                .error(String.format(
                        "Severe internationalization error: Internationalization bundle for locale '%s' not found!",
                        locale.toString()), e);
    }
    return String.format("No message found for key '%s'!", messageKey);
}

Solution

  • In this case, as inside the call to FacesContext.getCurrentInstance().addMessage you also call AbstractBean .getTranslation(String) you will also need to mock that method.

    Something like this:

    TrendBeanTest

    public class TrendBeanTest {
    
    @Tested
    TrendBean trendBean;
    @Injectable
    LoginBean loginBean;
    @Injectable
    Session session;
    @Injectable
    ITrendManager manager;
    @Injectable
    IUserManager userManager;
    @Injectable
    User user;
    
    @Test
    public void testAddChartPoint(@Mocked FacesContext fakeContext, @Mocked AbstractBean abstractBean) {
    
        new NonStrictExpectations() {
    
            {
                session.isLoggedIn();
                result = true;
                session.getUser();
                result = user;
                manager.addPointToUser((User) any, (ChartPoint) any);
                FacesContext.getInstance();
                result = fakeContext;
                abstractBean.getMessage(anyString); result = "foo";
            };
        };
    
        Deencapsulation.setField(trendBean, "point", new ChartPoint());
    
        assertEquals(null, trendBean.addChartPoint());
    
        new Verifications(){{
            fakeContext.addMessage(withNull(), (FacesMessage)any); 
        }};
    }
    }
    

    Note: I'm doing this from the top of my head with no IDE, so maybe I've overtyped something.