【问题标题】:How to use thenAnswer with method which returns void如何将 thenAnswer 与返回 void 的方法一起使用
【发布时间】:2012-01-06 09:28:43
【问题描述】:

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

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));

【问题讨论】:

  • 在您的更新中,括号放错了位置。我不确定这是否是您错误的原因,因为其余部分看起来还可以。所以应该是doAnswer( ... ).when( dataReqDao ).persist( ... ); 有帮助吗?
  • @David:谢谢大卫。实际上我更正了,但忘记更新我的问题。

标签: unit-testing mockito


【解决方案1】:

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

例如如下:

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

... // Validate newObj

【讨论】:

  • 这不会执行一个巧妙的测试,因为 ArgumentCaptor 不会在调用时捕获对象的状态,而只是捕获 objectId。所以即使你在 dao 调用之后在你的方法中使用了 setter,你的测试也会是绿色的。但是一个好的测试应该在每次功能更改时都失败。我写了我的建议作为对帖子的回答。
【解决方案2】:

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

 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 调用之前还是之后设置属性,captor 都没有关系。然而,每次功能更改都应该失败。这是我关于这个案例的文章:

https://akcasoy.wordpress.com/2015/02/03/how-to-ensure-quality-of-junit-tests/(上面的 then 存根是一种比 InOrder 方法更好的方法)

【讨论】:

    【解决方案3】:
    Myclass newObj = new Myclass();  
    

    那条线让我很困扰。如果您使用依赖注入,您应该让您的工厂向您发送该对象的一个​​实例。然后,当您创建单元测试时,您可以让测试工厂发送一个 MyClass 的模拟实例,单元测试也可以访问该实例。然后你可以使用 axtavt 的 captor 来查看它是否真的做了它应该做的事情。单元测试的方式没有问题,只是 any() 有点弱,因为您知道它正在传递该类型的对象-您想在测试中知道该对象是否是您想要的并且尚未修改。

    【讨论】:

      猜你喜欢
      • 2015-10-27
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 2015-10-03
      • 2020-12-07
      相关资源
      最近更新 更多