我正在尝试修复一些现有的 junit/mockito 测试,由于重写以使用 Dao's 而不得不更改这些测试。
所以我有这个论点俘虏:-
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);
所以我试图以某种方式将俘虏分配/绑定到"更新注册状态..."。方法,但我似乎找不到一种方法来做到这一点,主要是因为该方法必须采用字符串参数,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());
但是,值对象为空,在调试测试时,我可以确认正在调用有问题的方法。
如果我在这里错过了一些琐碎的事情,请提前道歉,再次感谢您的所有帮助!
这个问题似乎比最初想象的要困难得多。有关此内容的更多详细信息,请参见下文。
Mockito需要查看的Matcher
实例必须实现CapturesArguments
接口。因此,解决方案是实现一个AndMatcher
,该将委托给其子匹配器并实现CapturesArguments
。它将委派给所有在CapturesArguments.captureFrom(Object)
时也实现CapturesArguments
的子匹配器。请注意,CapturesArguments
是一个Mockito内部接口。
以下解决方案不起作用,因为 Mockito 看到的Matcher
实例没有实现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();
您还可以使用capture
方法实现自己的ArgumentCaptor
,该方法将采用额外的匹配器实例。
你的问题并不完全清楚,但我从中得到了以下几点:
- 你有一个
CustomerDao
的模拟. - 您的测试(间接(调用此模拟的
updateRegisterStatusToCurrentByCustomerNumber()
方法,向其传递String
标识符。 -
updateRegisterStatusToCurrentByCustomerNumber()
在内部对Customer
对象执行某些操作。 - 您希望测试有关相关对象
Customer
的内容。
如果这些是正确的,那么你对模拟的工作原理有一个根本性的误解。对Customer
对象执行某些操作的内部代码?在此测试中,该代码不存在。它从未被召唤过。CustomerDao
的模拟版本通过简单地返回测试设置代码告诉它的内容来响应您的updateRegisterStatusToCurrentByCustomerNumber()
调用,无论是null
、精心制作的示例对象还是其他模拟。它从不调用实际的CustomerDao
代码,因为模拟的全部意义在于使测试不依赖于该代码,以便该代码中的错误不会在整个依赖项树中级联测试失败。
为了测试CustomerDao.updateRegisterStatusToCurrentByCustomerNumber()
的内部行为,你需要创建单独的测试,直接在非模拟CustomerDao
上调用CustomerDao
方法,其他一切都是模拟的。