2013-04-15 40 views
2

鉴于传统应用程序有1500个spring.xmls。我想写一个服务的单元测试。我深深地依赖于地狱。我必须接受应用程序,没有出路。在纠结的春天背景下进行单元测试

所以我们使用spring-3.something和mockito-1.9,我想要测试服务的好方法。较新的代码大量使用@Autowired注释。

这个服务间接地使用了我实际上想在测试中使用的〜25个助手(工厂方法等)以及我对这个测试不感兴趣的〜25个对象。

我目前尝试以上述方式设置上下文,但我对@Mock,@InjectMocks,@Autowired的影响感到困惑。

我的测试如下。我需要帮助才能正确设置它。

问题:

  • 是什么@InjectMocks的实际效果?
  • 我该如何决定(技术上)哪些自动布线的豆子真的被使用,哪些被mock取代?
  • 我知道,我滥用嘲讽获得假货。是否有一种更简单的方法来获得单线的假货?
  • * 请注意,我想明白这一点,因为我有这样的服务... *

这里的负载是我的示例:

@ContextConfiguration(locations = { 
    "classpath:/some/path/MainTestConfig.spring.xml" 
}) 
@RunWith(SpringJUnit4ClassRunner.class) 
public class SampleTest { 

    // ***   Uninteresting Dependencies to be mocked  *** // 
    @Mock Mock1 mock1; 
    @Mock Mock2 mock2; 

    /** Service under test */ 
    @Autowired 
    SomeService service; 

    // ***   Tightly coupled helpers to be used    *** // 
    @Autowired Helper1 helper1 
    @Autowired Helper2 helpr2 

    @Before 
    public void setup() { 
     MockitoAnnotations.initMocks(SampleTest.class); 
    } 

    @Test 
    public void testSample() { 

     // prepare dummy context 
     SomeContext context = new Context(); 

     // define expected result 
     int expectedValue = 42; 

     //execute method under test, record result 
     Result actualResult = service.execute(context); 

     //make assertions on result 
     assertTrue(actualResult.getSomething()==expectedValue); 
    } 

} 
+0

我不明白为什么你会有'mock1'和'mock2'这些在你的测试中似乎没有关系,因为它们是不相关的。此外,助手似乎不被使用,在测试中得到验证。如果一切都是春天连线,为什么你想要它。我相信你实际上应该嘲笑紧密耦合的帮手,并验证相互作用。最终你也可以把这个测试写成一个大功能/特性测试,即不是单元测试,也不是集成测试,因此它会被放置在其他一些软件包中以显示你的同事的不同之处。 – Brice

+0

顺便问一下你是否尝试过Spring 3中的注释配置?如果你只需要注入一些依赖关系,这可能会很有用,并且这也可以用于mock(如果添加另一个maven依赖关系,则不需要使用springockito)。 – Brice

回答

4

我想发布这个作为一个单独的答案,因为这应该更好地解决您关于@Mock,@Autowired和@InjectMocks的实际问题。

@Mock:这标志着当调用MockitoAnnotations.initMocks(this)时应该创建为模拟的字段(使用mock(MyClass.class))。

@Autowired:标记一个字段,该字段应由Spring使用实现类/接口的bean进行分配。

@InjectMocks:标记应当由被的Mockito创建时MockitoAnnoations.initMocks(this)被称为场。它创建该类的一个实例,并将@Mock -annotated字段注入到此实例中。 (请参阅评论中对此声明的更正)。

分析:

@InjectMocks不使用Spring上下文和@Autowired兼容,因为InjectMock创建它不使用Spring实例的类的新实例。您需要使用Springockito。 (延迟更新)Springockito将允许您将模拟注入到Spring上下文中,从而将这些模拟用作Autowired候选项。它允许Mocks和Spys。在测试的同一个字段上使用ReplaceWithMockAutowired是一般惯例(如wiki上的示例所示)。

+0

**该语句不正确**:“... ...”InjectMock'创建了一个不使用Spring实例的类的新实例“。实际的Mockito行为是,如果该字段在mockito注入时已经有一个,它将永远不会创建一个实例。虽然我承认文档不清楚:['InjectMocks' Javadoc](http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html)。所以可以在spring管理bean中注入mock,**但是**我不推荐它,因为它在测试设置中增加了很多复杂性。 – Brice

+0

@Brice所以你是说如果你在测试的同一个字段中加入'@ Autowired'和'@InjectMocks'(需要Autowired来获取Spring bean),那么Spring bean将被使用,它将被更新注入测试中的嘲笑? –

+0

是的。 – Brice

2

第一个问题,你需要加载spring上下文做这个测试?通常当我有Spring项目时,我有一个UNIT测试每个类不会加载上下文文件。我将有一个不同的CONTEXT测试来加载上下文文件并验证它是否正确加载。如果你正在做真正的单元测试,我会建议不加载上下文。如果被测试的类使用@Autowired来分配依赖关系(因此没有setter),请使用Spring的ReflectionTestUtils来指定这些字段。

+0

好吧,我测试的单位是服务+其帮助者。要做到这一点,我需要设置*一些*上下文的助手和假人无所事事。手动设置这个上下文对于50个类是不可行的,所以我想在可能的情况下重用现有的spring配置,并在可行的地方注入mock。看来我没有得到“InjectMocks”呢...... – Bastl

+0

顺便说一句:什么是“真正的”单元测试?你认为什么是单位?我怀疑用“班级”或“方法”替换单元。我的单位是服务+助手。超越边界的一切都将被嘲笑/伪造。 – Bastl

+0

“真正的”单元测试是您的测试只接触ONE类(单元)的地方。所有其他类/依赖都被模拟。除了被测试的类外,我允许的唯一具体类是数据传输对象(DTO),它们只是数据持有者(字段,获取者,设置者)。 –