Java 创建依赖项只是为了能够进行单元测试
我刚刚创建了一个Java 创建依赖项只是为了能够进行单元测试,java,dependency-injection,junit4,dependency-management,Java,Dependency Injection,Junit4,Dependency Management,我刚刚创建了一个管理器,它处理一个超类,该超类扩展到整个代码库,并注册到某种超类管理器(SCM) 现在我想测试我的管理器,它只知道超类。我试图创建一个具体的SCM,但是,它依赖于第三方库,因此我在jUnit测试中没有做到这一点。现在的选项是模拟此SCM的所有实例 但是,直到现在一切都很好,当我的管理器处理SCM时,它返回我的管理器不知道或不关心的超类的子类。然而,这些孩子的身份对于我的测试(平等等)来说是至关重要的 由于我不能使用具体的SCM,我必须模拟调用SCM相应函数的结果,然而,这意味着我
管理器
,它处理一个超类
,该超类扩展到整个代码库,并注册到某种超类管理器
(SCM
)
现在我想测试我的管理器
,它只知道超类
。我试图创建一个具体的SCM
,但是,它依赖于第三方库,因此我在jUnit测试中没有做到这一点。现在的选项是模拟此SCM
的所有实例
但是,直到现在一切都很好,当我的管理器处理SCM
时,它返回我的管理器不知道或不关心的超类的子类。然而,这些孩子的身份对于我的测试(平等等)来说是至关重要的
由于我不能使用具体的SCM
,我必须模拟调用SCM
相应函数的结果,然而,这意味着我的测试和(间接地)我的管理者需要了解和关心超类的子类
检查代码库时,似乎没有更适合我的测试的位置(它已经维护了适当的实际依赖项)
为单元测试引入不必要的依赖关系是否值得
2012年12月18日更新
以下是我的问题的简化版本:
package some.package.declaration;
import some.open.source.framework.TopComponent;
import some.open.source.framework.WindowManager;
/**
* Own source code.
* Knows WindowManager and TopComponent; but no
* direct child of TopComponent.
*/
class TopComponentManager{
/**
*
*/
void efficientlyDoOperationsOnCurrentTopComponents(){
Set<TopComponent> currentTopComponents = get all current TopComponents from WindowManager;
Set<TopComponent> getNeededTopComponents(currentTopComponents);
do some operations on the current TopComponents;
...
...
}
void Set<TopComponent> getNeededTopComponents(Set<TopComponent> givenTopComponents){
Set<TopComponent> neededTopComponents = new HashSet<TopComponent>(givenTopComponents);
disregard and keep some TopComponents based on controls;
return neededTopComponents;
}
}
package some.package.declaration.test; // same project as TopComponentManager
import jmockit;
import some.open.source.framework.TopComponent;
import some.open.source.framework.WindowManager;
import own.source.code.childrenOfTopComponent.ChildTopComponent; // Don't want to; need to introduce package dependencies
import own.source.code.childrenOfTopComponent.AnotherChildTopComponent; // Don't want to; need to introduce package dependencies
class TopComponentManagerTest{
@Tested
TopComponentManager _topComponentManager;
@Mocked
WindowManager _windowManager;
@Mocked
ChildTopComponent _childTopComponent1; //extends TopComponent; unknown to both TopComponentManager and TopComponentManagerTest
@Mocked
AnotherChildTopComponent _childTopComponent2; //extends TopComponent; unknown to both TopComponentManager and TopComponentManagerTest
Set<TopComponent> _currentTopComponents = new HashSet<TopComponent>();
@Before
void setUp() throws Exception {
_currentTopComponents.add(_childTopComponent1);
_currentTopComponents.add(_childTopComponent2);
}
void testgetNeededTopComponents(){
Deencapsulation.invoke(_topComponentManager, "getNeededTopComponents", _currentTopComponents);
new Verifications(){{
verify that only _childTopComponent2 is returned;
}};
}
}
package some.package.declaration;
导入一些.open.source.framework.TopComponent;
导入一些.open.source.framework.WindowManager;
/**
*自己的源代码。
*了解WindowManager和TopComponent;但是没有
*TopComponent的直接子级。
*/
类TopComponentManager{
/**
*
*/
void efficientlyDooperationOnCurrentTopComponents(){
Set-currentTopComponents=从WindowManager获取所有当前TopComponents;
设置GetNeedTopComponents(currentTopComponents);
对当前TopComponents执行一些操作;
...
...
}
无效集合GetNeedtTopComponents(集合givenTopComponents){
Set neededTopComponents=新哈希集(给定的TopComponents);
忽略并保留一些基于控制的顶级组件;
返回所需的组件;
}
}
包some.package.declaration.test;//与TopComponentManager相同的项目
导入jmockit;
导入一些.open.source.framework.TopComponent;
导入一些.open.source.framework.WindowManager;
导入own.source.code.childrenOfTopComponent.ChildTopComponent;//不想;需要引入包依赖项
导入own.source.code.childrenOfTopComponent.AnotherChildTopComponent;//不想;需要引入包依赖项
类TopComponentManagerTest{
@测试
TopComponentManager_TopComponentManager;
@嘲弄
WindowManager\u WindowManager;
@嘲弄
ChildTopComponent\u childTopComponent1;//扩展TopComponent;TopComponentManager和TopComponentManagerTest都未知
@嘲弄
另一个ChildTopComponent _childTopComponent2;//扩展TopComponent;TopComponentManager和TopComponentManagerTest都未知
Set _currentTopComponents=new HashSet();
@以前
void setUp()引发异常{
_currentTopComponents.add(_childTopComponent1);
_currentTopComponents.add(_childTopComponents2);
}
void testGetNeedTopComponents(){
Deencapsulation.invoke(_topComponentManager,“GetNeedTopComponents”,_currentTopComponents);
新的核查(){{
验证只返回了_childTopComponent2;
}};
}
}
可以看出,在测试TopComponentManager时,我必须验证确定的必要元素,这些元素在此包中是未知的。不确定这是否是您要查找的元素,但当调用模拟方法时:
SCM scmMock = Mockito.mock(SCM.class, Mockito.RETURNS_MOCKS);
// scmMock.someMethod() will return a mock
也许如果你能给出一些代码,那么给你一个答案就容易多了
另外,当管理器
只知道超类
时,如何调用超类管理器
?它是超类中的依赖项吗?如果是这种情况,那么<代码>超类有一个错误的依赖关系,您应该考虑从“代码>超类< /代码>中删除此项。
但是,如果您的经理不知道SCM
,而只知道超类
,然后您应该模拟超类
,因为管理器的测试不能依赖于其他组件的代码,您不应该创建不必要的依赖项。为什么不直接模拟TopComponent
例如:
@Mocked
TopComponent _childTopComponent1;
我最终解决了这个问题,创建了一个只包含我的测试类的新项目。这个测试类依赖于TopComponentManager
和分布在代码库中的所有子TopComponent
s。但是,依赖关系并不重要
通过这种方法,可以在这个项目中实现更多的测试,而不会对生产代码产生任何额外的依赖关系 谢谢,但我需要的是返回的模拟是某种类型的。在不创建依赖项的情况下,不可能将该类型引入测试类。我希望我能理解你的回答;如果我这样做,这将无法帮助,因为模拟返回类型必须是我需要的类型,因此必须知道该类型。我支持这一点。除非您使用instanceof检查TopComponent的类型,否则我认为没有理由不模拟它。如果您碰巧这样做了,那么也许您应该考虑将该逻辑转移到另一个组件。@TomVerelst@Koraktor I不能这样做;正如我所说,在测试getneedTopComponents
时,我需要根据不同的情况(当givenTopComponents
不同时)验证顶级组件的身份。不幸的是,这个例子相当简单,但不同的TopComponents有不同的