2012-02-03 94 views
0

我有一个测试方法。在其调用堆栈中,它调用一个实例使用JDBC与数据库聊天的DAO。我对于了解JDBC层会发生什么并不感兴趣,我已经为此做了测试,而且他们的工作非常出色。模拟方法没有直接调用JMock的单元测试

我想模拟,使用JMock,DAO层,所以我可以专注于测试下的这个方法的细节。这是我所拥有的基本表现形式。

@Test  
public void myTest() 
{ 
    context.checking(new Expectations() { 
      { 
       allowing(myDAO).getSet(with(any(Integer.class))); 
       will(returnValue(new HashSet<String>())); 
      } 
    }); 

    // Used only to show the mock is working but not really part of this test. 
    // These asserts pass. 
    Set<String> temp = myDAO.getSet(Integer.valueOf(12)); 
    Assert.assertNotNull(temp); 
    Assert.assertTrue(temp.isEmpty()); 

    MyTestObject underTest = new MyTestObject(); 
    // Deep in this call MyDAO is initialized and getSet() is called. 
    // The mock is failing to return the Set as desired. getSet() is run as 
    // normal and throws a NPE since JDBC is not (intentionally) setup. I want 
    // getSet() to just return an empty set at this layer. 
    underTest.thisTestMethod(); 
    ... 
    // Other assertions that would be helpful for this test if mocking 
    // was working. 
} 

它,从我已经学会了创造这个测试,我可以不使用JMock的嘲笑间接对象。或者我没有看到一个关键点。我希望下半场是真实的。

想法和谢谢。

回答

0

从这段代码中,我猜测MyTestObject使用反射或静态方法或字段来获取DAO,因为它没有构造函数参数。 JMock不会按类型替换对象(现在任何时候,都会有一群人推荐其他框架)。

这是故意的。 JMock的一个目标是突出对象设计的弱点,要求清洁依赖和集中行为。我发现在域对象中嵌入DAO/JDBC访问最终会让我陷入困境。这意味着域对象具有秘密依赖性,这使得它们更难理解和改变。我更愿意在代码中明确地表达这些关系。

所以你必须将模拟对象以某种方式放入目标代码中。如果你不能或不想这样做,那么你将不得不使用另一个框架。

P.S.的风格一点,你可以简化这个测了一下:

context.checking(new Expectations() {{ 
    allowing(myDAO).getSet(12); will(returnValue(new HashSet<String>())); 
}}); 

测试中,你应该知道什么是价值期待和饲料到这一点的期望。这使得更容易看到对象之间的值的流动。

+0

在setUp()中,我使用context.mock(MyDAO.class)来模拟myDAO。在MyTestObject的互操作中,MyDAO被实例化为'new'。 – DDus 2012-02-07 16:02:24

+0

那就是这个问题。你有一个我们看不到的隐式依赖。您现在必须决定是否要明确依赖或者使用其中一个更聪明的框架进行干预。我想你可以猜出哪一个我更喜欢:) – 2012-02-21 09:37:30

+0

我们用JMockit代替,但也考虑添加PowerMock的选项。 – DDus 2012-02-21 14:36:58