如何使用静态工厂方法和mocking进行协调?
许多人只会说:不要使用静态工厂方法,而要使用DI。
嗯,有时候你不能避免使用静态工厂方法。考虑以下应该熟悉的用例:
假设您有一个名为Option的类,就像在scala中一样。如果您想对所有缺少的值重用相同的实例,则无法避免使用静态工厂方法。
一旦你使用new Option(null)创建了一个新的option对象,你就不能一遍又一遍地返回相同的对象。
类似的用例是Integer.valueOf(),它将对小于128的值重用整数对象。不使用静态工厂方法是不可能的。
另一个优点是工厂方法比new关键字更具描述性。
那么,你们如何处理必须使用静态工厂方法,同时又想使用继承和mock呢?
谢谢。
发布于 2015-12-02 00:35:55
既然这是一个理论问题,我就给出一个理论上的答案。工厂范例是另一种理论的构建点:注入。如果您创建的对象是在需要时注入的,那么您只需注入您的模拟对象即可完成所有测试。有很多好的书/网页可以帮助你开始使用它。
发布于 2015-12-02 00:36:23
使用PowerMock可以模拟静态方法。考虑他们的Wiki page中的以下示例
@Test
public void testRegisterService() throws Exception {
long expectedId = 42;
// We create a new instance of test class under test as usually.
ServiceRegistartor tested = new ServiceRegistartor();
// This is the way to tell PowerMock to mock all static methods of a
// given class
mockStatic(IdGenerator.class);
/*
* The static method call to IdGenerator.generateNewId() expectation.
* This is why we need PowerMock.
*/
expect(IdGenerator.generateNewId()).andReturn(expectedId);
// Note how we replay the class, not the instance!
replay(IdGenerator.class);
long actualId = tested.registerService(new Object());
// Note how we verify the class, not the instance!
verify(IdGenerator.class);
// Assert that the ID is correct
assertEquals(expectedId, actualId);
}甚至可以只模拟一个特定的方法,而使用partial mocking保持其他方法不变。
发布于 2015-12-02 00:41:14
我的第一个选择是避免模拟任何东西,所以有没有静态工厂方法都没有区别。
也就是说,如果我真的想或需要嘲笑他们,我就会这么做。例如,假设您正在测试一个基于JSF的web应用程序,并且您想要模拟javax.faces.context.FacesContext对象。我将使用JMockit库(碰巧是我开发的)在测试中编写以下代码:
@Test
public void exampleTest(@Mocked final FacesContext ctx) {
// Call the code under test, which will at some point
// call FacesContext.getCurrentInstance(), then add an
// error message for display in the web page.
new Verifications() {{
FacesMessage msg;
ctx.addMessage(null, msg = withCapture());
assertEquals("The expected error message.", msg.getSummary());
assertNotNull(msg.getDetail());
}};
}在本例中,Faces.getCurrentInstance()是静态工厂方法,一旦类被模拟,它将自动返回一个模拟的FacesContext实例。
https://stackoverflow.com/questions/34025131
复制相似问题