如何测试使用会话参数的JSF bean方法?

时间:2013-07-28 17:23:35

标签: unit-testing jsf

我很难在我的JSF支持bean类上实现单元测试...例如,一些方法使用会话或请求参数,使用这种代码获得:

FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("paramKey");

我的问题是:如何测试从会话或请求中获取值的方法?

2 个答案:

答案 0 :(得分:9)

我通常做的是避免将静态方法调用到我想要测试的bean中。这意味着您当前的代码将被重构:

FacesContext.getCurrentInstance().getExternalContext()
    .getSessionMap().get("paramKey");

有没有办法用静态方法调用来测试它们?可能有,但他们给我带来了很多麻烦而不是帮助。所以最后我摆脱了它们并改变了我的设计。让第二个豆做它(你稍后会嘲笑)。在您的情况下,创建一个管理该功能的@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
    }

}

答案 1 :(得分:6)

这是possible to mock FacesContext,但这不太理想。 Mockito示例:

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的所有功能,但在必要时connect JSF managed beans to CDI相对容易。

JSF托管bean限制了您将类型注入的范围,但即使这样也会导致范围泄漏。例如,即使对象属于请求范围#{sessionScope},也可以将ExternalContext变量注入会话范围bean。可以通过writing your own JSF bean proxies克服此问题。

注意:大部分内容都是用Java EE 6编写的; Java EE 7可能会改进。