如何用 mockito 存根异步调用?
How to stub asynchronous calls with mockito?
假设我有两个 类 一起工作来执行这样的可调用:
public class blah {
@Autowired
private ExecutorServiceUtil executorServiceUtil;
@Autowired
private RestTemplate restClient;
public SomeReturnType getDepositTransactions(HttpHeaders httpHeaders) {
ExecutorService executor = executorServiceUtil.createExecuter();
try {
DepositTransactionsAsyncResponse asyncResponse = getPersonalCollectionAsyncResponse( httpHeaders, executor);
// do some processing
// return appropriate return type
}finally {
executorServiceUtil.shutDownExecutor(executor);
}
}
Future<ResponseEntity<PersonalCollectionResponse>> getPersonalCollectionAsyncResponse( HttpHeaders httpHeaders, ExecutorService executor) {
PersonalCollectionRequest personalCollectionRequest = getpersonalCollectionRequest(); // getPersonalCollectionRequest populates the request appropriately
return executor.submit(() -> restClient.exchange(personalCollectionRequest, httpHeaders, PersonalCollectionResponse.class));
}
}
public class ExecutorServiceUtil {
private static Logger log = LoggerFactory.getLogger(ExecutorServiceUtil.class);
public ExecutorService createExecuter() {
return Executors.newCachedThreadPool();
}
public void shutDownExecutor(ExecutorService executor) {
try {
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
log.error("Tasks were interrupted");
}
finally {
if (!executor.isTerminated()) {
log.error("Cancel non-finished tasks");
}
executor.shutdownNow();
}
}
}
如何使用 Mockito 对响应进行存根并立即 return 它?
我试过以下但我的 innovcation.args() returns [null]
PowerMockito.when(executor.submit(Matchers.<Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>> any())).thenAnswer(new Answer<FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>>() {
@Override
public FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> answer(InvocationOnMock invocation) throws Throwable {
Object [] args = invocation.getArguments();
Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> callable = (Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>) args[0];
callable.call();
return null;
}
});
您通过 而不是 在您的测试代码中使用您的 ExecutorServiceUtil
来做到这一点。我的意思是:您为您的生产代码提供了那个实用程序 class 的 mock!
那个模拟 return 一个 "same thread executor service";而不是 "real service"(基于线程池)。编写这样一个同线程执行程序实际上很简单 - 请参阅 here.
换句话说:您需要 两个 不同的单元测试:
- 您单独为
ExecutorServiceUtil
class 编写单元测试;确保它做了它应该做的事情(我认为:检查它 return 是一个非空的 ExecutorService 几乎就足够了!)
- 您为
blah
class 编写单元测试...使用模拟服务。突然之间,您 "it is async" 周围的所有问题都消失了;因为 "async" 部分消失了。
假设我有两个 类 一起工作来执行这样的可调用:
public class blah {
@Autowired
private ExecutorServiceUtil executorServiceUtil;
@Autowired
private RestTemplate restClient;
public SomeReturnType getDepositTransactions(HttpHeaders httpHeaders) {
ExecutorService executor = executorServiceUtil.createExecuter();
try {
DepositTransactionsAsyncResponse asyncResponse = getPersonalCollectionAsyncResponse( httpHeaders, executor);
// do some processing
// return appropriate return type
}finally {
executorServiceUtil.shutDownExecutor(executor);
}
}
Future<ResponseEntity<PersonalCollectionResponse>> getPersonalCollectionAsyncResponse( HttpHeaders httpHeaders, ExecutorService executor) {
PersonalCollectionRequest personalCollectionRequest = getpersonalCollectionRequest(); // getPersonalCollectionRequest populates the request appropriately
return executor.submit(() -> restClient.exchange(personalCollectionRequest, httpHeaders, PersonalCollectionResponse.class));
}
}
public class ExecutorServiceUtil {
private static Logger log = LoggerFactory.getLogger(ExecutorServiceUtil.class);
public ExecutorService createExecuter() {
return Executors.newCachedThreadPool();
}
public void shutDownExecutor(ExecutorService executor) {
try {
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
log.error("Tasks were interrupted");
}
finally {
if (!executor.isTerminated()) {
log.error("Cancel non-finished tasks");
}
executor.shutdownNow();
}
}
}
如何使用 Mockito 对响应进行存根并立即 return 它?
我试过以下但我的 innovcation.args() returns [null]
PowerMockito.when(executor.submit(Matchers.<Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>> any())).thenAnswer(new Answer<FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>>() {
@Override
public FutureTask<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> answer(InvocationOnMock invocation) throws Throwable {
Object [] args = invocation.getArguments();
Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>> callable = (Callable<ResponseEntity<OrxPendingPostedTrxCollectionResponseV3>>) args[0];
callable.call();
return null;
}
});
您通过 而不是 在您的测试代码中使用您的 ExecutorServiceUtil
来做到这一点。我的意思是:您为您的生产代码提供了那个实用程序 class 的 mock!
那个模拟 return 一个 "same thread executor service";而不是 "real service"(基于线程池)。编写这样一个同线程执行程序实际上很简单 - 请参阅 here.
换句话说:您需要 两个 不同的单元测试:
- 您单独为
ExecutorServiceUtil
class 编写单元测试;确保它做了它应该做的事情(我认为:检查它 return 是一个非空的 ExecutorService 几乎就足够了!) - 您为
blah
class 编写单元测试...使用模拟服务。突然之间,您 "it is async" 周围的所有问题都消失了;因为 "async" 部分消失了。