如何使用thenAnswer返回void的方法

时间:2012-01-06 09:28:44

标签: unit-testing mockito

我想对以下方法进行单元测试

public void addRecord(Record record)  
{  
   Myclass newObj = new Mycalss();  
   // It creates newObj object, set some values using record object.  
   // and it adds the newObj in daatbase.
   dataReqDao.persist(newObj);
}    

我已经模拟了dataReqDao.persist方法但是如何验证是否将正确的值复制到newObj对象中?我想获得newObj对象。

我认为thenAnswer将是检索newObj即方法参数的合适方法,但不知道如何使用返回void的方法。

更新
我试过了

doAnswer(new Answer<Myclass>() {
              public Myclass answer(InvocationOnMock invocation) {
                  Object[] args = invocation.getArguments();
                  return (Myclass)args[0];
              }

        }).when(dataReqDao.persist(any(Myclass.class)));

修改
它应该是(谢谢大卫)

 doAnswer(new Answer<Myclass>() {
                  public Myclass answer(InvocationOnMock invocation) {
                      Object[] args = invocation.getArguments();
                      return (Myclass)args[0];
                  }

            }).when(dataReqDao).persist(any(Myclass.class));

3 个答案:

答案 0 :(得分:5)

您可以创建一个自定义argument matcher来检查该对象的字段,或使用argument captor捕获该对象以供进一步检查。

例如,如下:

ArgumentCaptor<Myclass> c = ArgumentCaptor.forClass(Myclass.class);
verify(dateReqDao).persist(c.capture());
Myclass newObj = c.getValue();

... // Validate newObj

答案 1 :(得分:1)

您需要使用 thenAnswer (或然后,我个人更喜欢),因此您可以在方法调用时断言/验证值,在方法

 when(dataReqDao.persist(newObj)).then(new Answer<Void>() {
        @Override
        public Void answer(final InvocationOnMock invocation) {
            Myclass newObjActual = (Myclass) invocation.getArguments()[0];

            // Control
            assertEquals(..., newObjActual.getX());
            assertEquals(..., newObjActual.getY());
            return null;
        }
    });

 // Run Test
 x.addRecord(record);

以下是详细说明:https://akcasoy.wordpress.com/2015/04/09/the-power-of-thenanswer/(用例2)

ArgumentCaptor不会以巧妙的方式进行测试。当你改变这样的方法时:

public void addRecord(Record record)  
{  
   Myclass newObj = new Mycalss();  
   dataReqDao.persist(newObj);

   // first persist, than set attributes
   newObj.setX(..);
}  

..你的Captor测试仍在运行,但它应该失败。由于ArgumentCaptor在调用时不捕获对象的状态,而只捕获objectId,因此对于捕获者来说,无论是在dao调用之前还是之后设置属性都无关紧要。然而,每次功能变化都会导致良好的测试失败。以下是关于此案例的文章:

https://akcasoy.wordpress.com/2015/02/03/how-to-ensure-quality-of-junit-tests/(上面使用然后的方法比使用InOrder方法的方法更好)

答案 2 :(得分:0)

Myclass newObj = new Myclass();  

那条线让我烦恼。如果您使用依赖注入,您应该让工厂向您发送该对象的实例。然后,当您创建单元测试时,您可以让测试工厂发送MyClass的模拟实例,单元测试也可以访问该实例。然后你可以使用axtavt的捕获者来查看它是否真的按照它应该做的去做。单元测试的方式没有任何问题,只是因为你知道它传递的是那种类型的对象,所以任何()都是弱的 - 你在测试中想知道的是对象是否是是你想要的并且没有被修改过的那个。