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有不同的