EDIT:为可读性清理了问题。请忽略10月31日前的评论
在我们的应用程序堆栈中,我们使用许多较小的jar模块,这些模块组合成最终的web应用程序。一个模块定义JSF特性,比如实现这个ViewScope。
现在,除了集成测试,我们希望能够对每个部分进行单元测试,因此需要一种方法来模拟一个完整的Faces上下文(通过包装器访问)来测试使用它的类。
这里的重要部分是complete,这意味着它必须有一个初始化的ViewMap
,因为这是我们的ViewScope
放置对象的地方。
我试过不同的方法:
1) shale-test:我已经走得最远了,但不幸的是这个项目已经退休了。
到目前为止,我已经将FacesContext包装在一个Provider中,这允许我用一个mock FacesContext替换它进行测试。我还修改了AbstractViewControllerTestCase的页实现,以包含一个应用程序上下文。然而,当调用MockedFacesContext.getViewRoot().getViewMap()
时,这将抛出UnsupportedOperationException
。原因似乎是MockApplication没有实例化此方法调用所需的Application.defaultApplication(它是null)。这似乎是页岩测试的限制。
2) JMock或mockito在我看来,这些似乎并没有真正模拟任何东西,因为大多数成员将保持为空。不知道JMock或mockit是否可以调用适当的初始化方法。
3)自定义Faces Mocker:对我来说,这似乎是唯一剩下的选择,但我们真的没有时间来分析Faces是如何初始化的,并重新创建模拟目的的行为。也许有人以前没有这样做过,可以分享主要的路径点和陷阱?
或者是否有其他方法来模拟FacesContext在web应用程序之外?
我会选择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.
*/
}
}
一些阅读:
- http://code.google.com/p/powermock/wiki/MockitoUsage