【问题标题】:How do I mock a JSF FacesContext with a ViewMap for Unit Tests outside an actual web application?如何在实际 Web 应用程序之外使用 ViewMap 模拟 JSF FacesContext 以进行单元测试?
【发布时间】:2011-11-12 04:30:35
【问题描述】:

编辑:清理了问题的可读性。请忽略截至 10 月 31 日的 cmets。

在我们的应用程序堆栈中,我们使用许多较小的 jar 模块,这些模块组合成最终的 Web 应用程序。一个模块定义了 JSF 特性,例如实现 this ViewScope。

现在除了集成测试,我们希望能够对每个部分进行单元测试,因此需要一种方法来模拟完整的 Faces 上下文(通过包装器访问)来测试使用它的类。

这里的重要部分是complete,这意味着它必须有一个初始化的ViewMap,因为这是我们的ViewScope 放置其对象的地方。


我尝试了不同的方法:

1) shale-test:我在这方面走得最远,但不幸的是该项目已退役。

到目前为止,我已经将 FacesContext 包装在一个 Provider 中,它允许我用一个 Mocked FacesContext 替换它以进行测试。我还修改了 AbstractViewControllerTestCase 的页岩实现以包含应用程序上下文。

但是,当调用 MockedFacesContext.getViewRoot().getViewMap() 时,会抛出 UnsupportedOperationException。原因似乎是 MockApplication 没有实例化此方法调用所需的 Application.defaultApplication (它为空)。这似乎是页岩测试的限制。


2) JMock 或 mockito 在我看来,这些似乎并没有真正嘲笑任何东西,因为大多数成员将保持为空。不知道 JMock 或 mockito 是否真的可以调用propper初始化方法。


3) 自定义 Faces Mocker: 对我来说,这似乎是唯一剩下的选择,但我们真的没有时间分析 Faces 是如何初始化的并重新创建用于模拟目的的行为。也许有人以前没有这个并且可以分享主要的航点和陷阱?


或者有没有其他方法可以在 Web 应用程序之外模拟 FacesContext?

【问题讨论】:

  • 我不知道 Jmock 部分,但异常只是想告诉您当前运行时类路径中缺少 javax.el.ELContext 类。一个明显的解决方法是将它包含在运行时类路径中。配置项目的构建路径以包含目标运行时的库(servletcontainer/appserver)。
  • 根据您的编辑,EL API 是 JSF API 的依赖项。它被用来解决那些#{} 的事情。 EL API 通常已经由目标运行时(Tomcat、JBoss、Glassfish 等)提供。
  • 啊,很好。包括 EL 依赖项有帮助。模拟的上下文仍然非常不可用,但它是一步一步。也许有人仍然对如何将 jmock 与 facesContext 一起使用或如何对使用 FacesContext.getcurrentinstance() 的类进行单元测试(如上面提到的 ViewScope 实现)有更多的想法。 (看来我不会绕过 FacesContext Wrapper/Provider..?但是模拟 FacesContext 的最佳方法是什么?)
  • Shale 退役并不意味着您无法获得它。最后一个版本在 Apache Attic 中,可以下载。我使用它,它非常适合模拟 FacesContext
  • 是的,我在包含 EL 依赖项后再次尝试了页岩,并获得了某种面孔上下文。但是它的功能并不完整:调用getViewRoot().getViewMap() 将抛出UnsupportedOperationException 这可以追溯到MockApplication 没有实例化私有字段Application.defaultApplication(调用ApplicationFactory.getApplication() 时)。我不知道这是否有效,或者只是缺乏进一步的发展。

标签: jsf junit mocking facescontext


【解决方案1】:

我会选择PowerMock+Mockito:

来自您的链接:

private Map<String,Object> getViewMap() {
    return FacesContext.getCurrentInstance().getViewRoot().getViewMap();
}

在测试中:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ FacesContext.class });
public class TheTest {
    /*
     * fake viewMap.
     */
    private Map<String,Object> viewMap = Maps.newHashMap() // guava

    /**
     * mock for FaceContext
     */
    @Mock
    private FacesContext faceContext;

    /**
     * mock for UIViewRoot
     */
    @Mock
    private UIViewRoot uiViewRoot;

    @Before
    public void setUp() {
        Mockito.doReturn(this.uiViewRoot).when(this.faceContext).getViewRoot();
        Mockito.doReturn(this.viewMap).when(this.uiViewRoot).getViewMap();

        PowerMock.mockStatic(FacesContext.class);
        PowerMock.doReturn(this.faceContext).when(FacesContext.class, "getCurrentInstance");
    }

    @Test
    public void someTest() {
        /*
         * do your thing and when  
         * FacesContext.getCurrentInstance().getViewRoot().getViewMap(); 
         * is called, this.viewMap is returned.
         */
    }
}

一些阅读:

【讨论】:

  • 听起来很有希望。回到应用程序的前端后,我会立即尝试。不过这可能需要一段时间,所以请耐心等待赏金;)
  • 点是帮助没有得到赏金;o
猜你喜欢
  • 1970-01-01
  • 2014-06-03
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
相关资源
最近更新 更多