jUnit:NPE on private member initialization
-
27-10-2019 - |
Question
Have jUnit
test, which initializes my bean:
ShowProducts sp = new ShowProducts();
got NullPointerException
on following line in ShowProducts.java:
private Locale locale = FacesContext.getCurrentInstance().getViewRoot()
.getLocale();
...
public Locale getLocale() {
return locale;
}
public String getLanguage() {
return locale.getLanguage();
}
public void localize() {
String localeParam = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get("lang");
locale = new Locale(localeParam);
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
How to initialize properly this field in test?
EDIT:
faces-config:
<application>
<locale-config>
<default-locale>ru</default-locale>
<supported-locale>ua</supported-locale>
</locale-config>
<resource-bundle>
<base-name>msg</base-name>
<var>m</var>
</resource-bundle>
</application>
.xhtml:
<h:form>
<h:commandLink action="#{showProducts.localize}" includeViewParams="true"
rendered="#{showProducts.language=='ua'}">
#{m.rus}.
<f:param name="lang" value="ru"/>
</h:commandLink>
<h:commandLink action="#{showProducts.localize}" includeViewParams="true"
rendered="#{showProducts.language=='ru'}">
#{m.ukr}.
<f:param name="lang" value="ua"/>
</h:commandLink>
</h:form>
Solution
Apparently your JSF FacesContext is not configured properly (I do no know much about faces, but I assume that setting them up and running in jUnit test is pretty complicated). However, there is help underway - use mocking.
In your test case, you like to assure that: - ShowProducts retrieves proper locale out of faces context / view root - does other things properly.
I recommend you to use jmockit. Your test case would become something like:
@Test
public void testShowProducts(@Cascading final FacesContext facesContext) {
final Locale locale = new Locale(...)
new Expectations() {
{
FacesContext.FacesContext.getCurrentInstance().getViewRoot().getLocale();
returns(locale);
}
};
ShowProducts sp = new ShowProducts();
... do your assertions other stuff there
}
This techuique is applicable to lot of contextes and simplifies test code greatly.
OTHER TIPS
Accessing static methods makes writing tests hard.
Either pass the Locale with the constructor or use a setter.
The easiest change would be to add a second constructor with a Locale as parameter and use it for the unittest. The default constructor then initializes the field from the FacesContext.
Towards a cleaner design you should extract a Localizer
where you handle all the localization, so to separate then ShowProducts
which doesn't need the FacesContext
from the Localizer
which does.
The Localizer would be something like:
public class Localizer {
public void localize() {
String localeParam = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get("lang");
locale = new Locale(localeParam);
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
}
This has nothing to do with ShowProducts
. Not sure what you need getLanguge()
for.