我很难在我的 JSF 支持 bean 类上实现单元测试......例如,一些方法使用会话或请求参数,使用这种代码获得:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("paramKey");
.
我的问题是:如何测试从会话或请求中获取值的方法?
我很难在我的 JSF 支持 bean 类上实现单元测试......例如,一些方法使用会话或请求参数,使用这种代码获得:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("paramKey");
.
我的问题是:如何测试从会话或请求中获取值的方法?
我通常做的是避免将静态方法调用到我要测试的 bean 中。这意味着要重构您当前的代码:
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().get("paramKey");
有没有办法用它们的静态方法调用来测试它们?可能有,但他们给我带来的麻烦多于帮助。所以最后我摆脱了它们并改变了我的设计。只需让第二个 bean 来完成(稍后您将对其进行模拟)。在您的情况下,创建一个@SessionScoped
管理该功能的 bean:
@ManagedBean
@SessionScoped
public class SessionBean{
public Object getSessionParam(String paramKey){
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().get(paramKey);
}
}
并将该 bean 注入每个需要它的 bean 中(我通常从具有它的抽象 bean 扩展我的视图/请求 bean,因此不必在每个 bean 中实现它):
@ManagedBean
@RequestScoped
public class RequestBean{
@ManagedProperty(value="#{sessionBean}")
private SessionBean sessionBean;
public void accessSessionParam(){
sessionBean.getSessionParam("name");
}
}
这样您就可以通过您的辅助轻松访问静态方法SessionBean
。那么,如何测试呢?只需创建它的模拟(例如使用Mockito):
public class Test{
public void test1(){
SessionBean sb = Mockito.mock(SessionBean.class);
//Mock your 'getSessionParam' method
ValueBean vb = new ValueBean();
Mockito.when(sb.getSessionParam(Mockito.anyString()).thenReturn(vb);
//Create your bean to test and set your mock to it
RequestBean rb = new RequestBean();
rb.setSessionBean(sb);
//here you can test your RequestBean assuming
//sessionBean.getSessionParam()
//will return vb for every single call
}
}
可以模拟FacesContext
,但这并不理想。模拟示例:
import javax.faces.context.FacesContext;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public abstract class ContextMocker extends FacesContext {
private ContextMocker() {}
private static final Release RELEASE = new Release();
private static class Release implements Answer<Void> {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
setCurrentInstance(null);
return null;
}
}
public static FacesContext mockFacesContext() {
FacesContext context = Mockito.mock(FacesContext.class);
setCurrentInstance(context);
Mockito.doAnswer(RELEASE)
.when(context)
.release();
return context;
}
}
如果您的平台支持它,那么首选CDI而不是 JSF 托管 bean。CDI 具有静态依赖检查并注入代理以防止范围泄漏。CDI 不支持 JSF 的所有特性,但在必要时将 JSF 托管 bean 连接到 CDI相对容易。
JSF 托管 bean 限制了您注入类型的范围,但即使这样也可能导致范围泄漏。例如,#{sessionScope}
即使对象属于请求范围,变量也可以注入到会话范围 bean 中ExternalContext
。可以通过编写自己的 JSF bean 代理来克服这个问题。
注意:大部分内容是在考虑 Java EE 6 的情况下编写的;Java EE 7 可能会有所改善。