模拟FacesContext

mko*_*yak 18 groovy jsf unit-testing mocking facescontext

我试图将一些单元测试添加到JSF应用程序.此应用程序并非严重依赖任何最佳实践,因此许多服务方法使用FacesContext从托管会话bean中提取数据,如下所示:

(这是在util类中)

  public static Object getPageBean(String beanReference) {
      FacesContext fc = FacesContext.getCurrentInstance();
      VariableResolver vr = fc.getApplication().getVariableResolver();
      return vr.resolveVariable(fc, beanReference);
  }
Run Code Online (Sandbox Code Playgroud)

嘲笑这个最好的方法是什么?我正在使用groovy所以我还有一些选项来创建我通常无法创建的类.

McD*_*ell 13

您可以在运行测试之前FacesContext.getCurrentInstance通过调用返回模拟上下文setCurrentInstance(FacesContext).该方法受到保护,但您可以通过反射或扩展来访问它FacesContext.有使用一个的Mockito示例实现在这里.


Ala*_*Dee 8

这个网址提供了一篇非常好的文章:http: //illegalargumentexception.blogspot.com/2011/12/jsf-mocking-facescontext-for-unit-tests.html

你有托管bean:

 package foo;

import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@RequestScoped
public class AlphaBean {
  public String incrementFoo() {
    Map<String, Object> session = FacesContext.getCurrentInstance()
        .getExternalContext()
        .getSessionMap();
    Integer foo = (Integer) session.get("foo");
    foo = (foo == null) ? 1 : foo + 1;
    session.put("foo", foo);
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

你存在FacesContext:

package foo.test;

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后编写单元测试:

@Test
  public void testIncrementFoo() {
    FacesContext context = ContextMocker.mockFacesContext();
    try {
      Map<String, Object> session = new HashMap<String, Object>();
      ExternalContext ext = mock(ExternalContext.class);
      when(ext.getSessionMap()).thenReturn(session);
      when(context.getExternalContext()).thenReturn(ext);

      AlphaBean bean = new AlphaBean();
      bean.incrementFoo();
      assertEquals(1, session.get("foo"));
      bean.incrementFoo();
      assertEquals(2, session.get("foo"));
    } finally {
      context.release();
    }
  }
Run Code Online (Sandbox Code Playgroud)


Cod*_*und 6

您可以使用PowerMock这个框架,它允许您使用额外功能扩展Mockito等模拟库.在这种情况下,它允许您模拟静态方法FacesContext.

如果您使用的是Maven,请使用以下链接检查所需的依赖项设置.

使用这两个注释注释您的JUnit测试类.第一个注释告诉JUnit使用运行测试PowerMockRunner.第二个注释告诉PowerMock准备模拟FacesContext该类.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ FacesContext.class })
public class PageBeanTest {
Run Code Online (Sandbox Code Playgroud)

模拟FacesContext使用PowerMock和使用verify()的Mockito,以检查resolveVariable()被称为与预期的参数.

@Test
public void testGetPageBean() {
    // mock all static methods of FacesContext
    PowerMockito.mockStatic(FacesContext.class);

    FacesContext facesContext = mock(FacesContext.class);
    when(FacesContext.getCurrentInstance()).thenReturn(facesContext);

    Application application = mock(Application.class);
    when(facesContext.getApplication()).thenReturn(application);

    VariableResolver variableResolver = mock(VariableResolver.class);
    when(application.getVariableResolver()).thenReturn(variableResolver);

    PageBean.getPageBean("bean_reference");

    verify(variableResolver)
            .resolveVariable(facesContext, "bean_reference");
}
Run Code Online (Sandbox Code Playgroud)

我创建了一篇博文,更详细地解释了上面的代码示例.


mko*_*yak 2

就我而言,我能够用纯粹的常规来嘲笑它。我提供了它可以返回的 MockBeans 映射:

private FacesContext getMockFacesContext(def map){
        def fc = [
          "getApplication": {
            return ["getVariableResolver": {
              return ["resolveVariable": { FacesContext fc, String name ->
                return map[name]
              }] as VariableResolver
            }] as Application
          },
          "addMessage": {String key, FacesMessage val ->
            println "added key: [${key}] value: [${val.getDetail()}] to JsfContext messages"
          },
          "getMessages": {return null}
        ] as FacesContext;
        return fc;
      }
Run Code Online (Sandbox Code Playgroud)