在项目中,我正在研究我们一堆常用的助手。考虑以下示例:
public class ServiceHelper {
public HttpServletRequest() getRequest() { ... }
public Model getModel() { ... }
public UserCache getUserCache() { ... }
public ComponentContainer getComponentContainer() { ... }
}
想象一下,我们拥有的每个Web服务都在整个应用程序中使用此助手。然后,为了测试这些服务,我需要嘲笑它。每一次。但是,如果我创建某种工厂,那就像:
一样public class ServiceHelperMockStore {
public static ServiceHelper create() {
return init();
}
public static ServiceHelper create(final Model model) {
final ServiceHelper helper = init();
when(helper.getModel()).thenReturn(model);
return helper;
}
private static ServiceHelper init() {
final ServiceHelper helper = mock(ServiceHelper.class);
final HttpServletRequest request = mock(HttpServletRequest.class);
final Model model = mock(Model.class);
final UserCache userCache = mock(UserCache.class);
final ComponentContainer container = mock(ComponentContainer.class);
final BusinessRules businessRules= mock(BusinessRules.class);
final ModelTransformer modelTransformer = mock(ModelTransformer.class);
when(helper.getRequest()).thenReturn(request);
when(helper.getModel()).thenReturn(model);
when(helper.getUserCache()).thenReturn(userCache);
when(helper.getComponentContainer()).thenReturn(container);
when(container.getComponent(BusinessRules.class)).thenReturn(businessRules);
when(componentContainer.getComponent(ModelTransformer.class)).thenReturn(modelTransformer);
return helper;
}
}
这个工厂非常适合我的目的,并且通常可以完全避免在实际的测试套件中使用"模拟"one_answers"当"。相反,我可以执行以下操作:
@RunWith(MockitoJUnitRunner.Silent.class)
public class ModelServiceTest {
private final Model model = new Model();
private final ServiceHelper serviceHelper = ServiceHelperMockStore.create(model);
private final BusinessRules businessRules = serviceHelper.getComponentContainer().getComponent(BusinessRules.class);
private final ModelType modelType1 = new ModelType();
private final ModelType modelType2 = new ModelType();
private final ModelService modelService = new ModelService(serviceHelper);
@Before
public void setUp() {
modelType1.setItemId("item1");
modelType2.setItemId("item2");
model.setTypes(modelType1, modelType2);
when(businessRules.get("type")).thenReturn(modelType1);
}
...tests...
}
因此,我可以访问预定义的模型,而不是在ModelservicEtest中创建许多模型,例如:
BusinessRules businessRules = serviceHelper.getComponentContainer().getComponent(BusinessRules.class);
这甚至反映了我的助手的API。另外,我可以向工厂方法或使用某些不同的方法提供自己的模拟或存根传递参数。
我唯一的问题是 decessareStubbingException 被Mockito抛出,因为通常我不使用每个测试文件创建的所有固执。因此,我必须使用 mockitoJunitrunner.silent runner来保持错误,并且根据Mockito API文档,不建议使用。
因此,我正在寻求建议在这种情况下必须选择哪种方法。我是做正确的还是有其他方法?或者,也许,使用这种工厂是一种与单位测试有关的编程方式,因为它隐藏了一些初始化并使发生的事情变得不那么明显,因此我必须在测试套装之间简单地对我的代码进行简单的副本?
您需要在不同地方需要这种相同的复杂模拟配置的事实表明,您的代码违反了demeter的法律 (不要与陌生人交谈(。/p>
单元只能获得它实际与之相互作用的依赖关系(仅仅是从中获得另一个依赖性(。
因此,我可以访问预定义的
,而不是在ModelservicEtest中创建很多模型
您的Unitests不仅是正确行为的验证,还包括最小示例如何使用剪切(测试的代码(。
剪切依赖项的配置是该示例的重要组成部分,应该轻松地访问测试的读者。
我强烈劝阻"模拟工厂",尤其是它们被转移到其他类(在test
文件夹中(。