2016-02-12 71 views
3

我试图修复一些现有的junit/mockito测试,因为重写使用Dao而不得不改变。Java&Mockito - 将一个参数传递给一个方法并捕获结果

所以我有这样的说法捕手: -

ArgumentCaptor<CustomerDao> customerDaoCaptor = ArgumentCaptor.forClass(CustomerDao.class); 

,我已经用这种方法之前得到的(客户)对象,这样我可以对它进行更多的测试。我通常会使用这样的: -

verify(customerDao, times(1)).saveOrUpdate(customerDaoCaptor.capture());  

,这样我就可以运行类似的测试: -

Customer customerActual = (Customer) customerDaoCaptor.getAllValues().get(0); 
assertEquals("PRE", customerActual.getExistingCustomer()); 

然而,在这种情况下,我不调用saveOrUpdate方法(该捕获器绑定到),但另一个Dao方法将唯一键作为参数,最终通过使用sql更新客户记录 - 即它不使用父对象的(Hibernate)saveOrUpdate方法。

我知道我可以测试它的调用,如: -

inOrder.verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(CUSTOMER_NUMBER); 

所以我想以某种方式分配/捕捉体结合“updateRegisterStatus ....”的方法,但我不能似乎找到了一种方法来做到这一点,主要是因为该方法必须采用字符串参数customer_number。

因此,在本质我试图做到这一点: -

inOrder.verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(CUSTOMER_NUMBER).customerDaoCaptor.capture() 

这显然是行不通的......

由于很多谷歌搜索并没有帮助我,我猜测我完全错了。

更新 - @SpaceTrucker

我试过下面的代码如你所说: -

CapturingMatcher<String> capturingMatcher = new CapturingMatcher<String>(); 
    verify(customerDao, times(1)).updateRegisterStatusToCurrentByCustomerNumber(
     argThat(
      org.hamcrest.Matchers.allOf(capturingMatcher, org.hamcrest.Matchers.notNullValue()) 
     ) 
    ); 
    List<String> values = capturingMatcher.getAllValues(); 

根据我的DAO实现: -

public void updateRegisterStatusToCurrentByCustomerNumber(String customerNumber) 

,它并通过测试成功,因为它不会失败,但它不会做我所需要的一切。这里的理想目标是以某种方式获取表示所更新的用户对象的对象 - 例如: -

Customer customerActual = (Customer) values.get(0); 
assertEquals("value", customerActual.getExistingCustomer()); 

的值。然而对象为空和调试测试,我可以确认问题的方法被调用。

如果我在这里错过了一些微不足道的事情,并再次感谢您的帮助,请提前道歉!

+0

不应该像'ArgumentCaptor customerCaptor = ArgumentCaptor.forClass(Customer.class)'一样定义捕获器;'?当获得捕获值时,这将为您节省铸件。 – SpaceTrucker

回答

1

这个问题似乎比首先想到的更困难。有关详情,请参阅下文。

Matcher实例Mockito确实需要看到必须实现CapturesArguments接口。因此,解决方案是实施一个AndMatcher,它将委托给其子代码匹配器并执行CapturesArguments。它将委托给也执行CapturesArguments的所有儿童匹配器,当时CapturesArguments.captureFrom(Object)。请注意0​​是一个Mockito内部接口。


以下解决方案不起作用, 因为Matcher情况下看到的Mockito,没有实现CapturesArguments接口,因此不会委派的说法捕捉到CapturingMatcher

ArgumentCaptor在内部使用CapturingMatcher。所以你可以使用Mockito.argThat和一个组合匹配器,它将包含一个CapturingMatcher和你喜欢的任何其他匹配器。

例如,给定接口

public interface ProductService { 
    List<Product> getProductsForCategory(Category category); 
} 

那么我们可以做到以下几点:

import org.hamcrest.Matchers; 

// ...  

CapturingMatcher<Category> capturingMatcher = new CapturingMatcher<Category>(); 
Mockito.verify(productService).getProductsForCategory(Mockito.argThat(Matchers.allOf(capturingMatcher, Matchers.notNullValue()))); 
List<Category> values = capturingMatcher.getAllValues(); 

你也可以实现自己的ArgumentCaptorcapture方法,将采取额外的匹配情况。

+0

嗨SpaceTrucker, 感谢您的帮助,但是对您的评论进行了仔细研究,但我仍然对此感到失望。你能不能更具体些,理想情况下,尽可能使用代码示例 - 我对Mockito非常陌生...... 再次感谢, Ian –

+0

@IanGallimore当您使用'ArgumentCaptor'时,它的类型参数应该始终是捕获的参数的类型,而不是调用方法的对象的类型,并且使用捕获器在其中一个方法参数上。 – SpaceTrucker

+0

如果你有时间和耐心,我已经更新了我原来的帖子。 –

0

你的问题是不完全清楚,但我从中得到以下几点:

  1. 你有CustomerDao的模拟。
  2. 您的测试(间接)调用此模拟的updateRegisterStatusToCurrentByCustomerNumber()方法,将String标识符传递给它。
  3. updateRegisterStatusToCurrentByCustomerNumber()在内部做一些Customer对象。
  4. 你想测试一下关于Customer对象的问题。

如果这些都是正确的,那么你对如何模拟工作有一个基本的误解。该内部代码对Customer对象做了些什么?在此测试中,该代码不存在。它从未被调用过。模拟版本CustomerDao通过简单地返回您的测试设置代码告诉它的内容(无论是null,精心制作的示例对象还是其他模拟)来响应您的调用。它永远不会调用实际的CustomerDao代码,因为模拟的全部要点是使测试不依赖于该代码,以便该代码中的错误不会在整个依赖关系树中级联测试失败。

要测试的CustomerDao.updateRegisterStatusToCurrentByCustomerNumber()内部行为,你将需要创建单独的测试,直接调用一个非模拟CustomerDaoCustomerDao方法,一切其他被嘲笑。

相关问题