Java 可完成的未来可用性和单元测试
我正在学习Java8Java 可完成的未来可用性和单元测试,java,unit-testing,testing,junit,mockito,Java,Unit Testing,Testing,Junit,Mockito,我正在学习Java8CompletableFuture,并以此结束 首先,你觉得这几行代码怎么样?我需要并行地向不同的服务发送请求,然后等待所有服务响应并继续工作 //service A CompletableFuture<ServiceAResponse> serviceAFuture = CompletableFuture.supplyAsync( () -> this.ServiceA.retrieve(serviceARequest), serviceAExec
CompletableFuture
,并以此结束
首先,你觉得这几行代码怎么样?我需要并行地向不同的服务发送请求,然后等待所有服务响应并继续工作
//service A
CompletableFuture<ServiceAResponse> serviceAFuture = CompletableFuture.supplyAsync(
() -> this.ServiceA.retrieve(serviceARequest), serviceAExecutorService
);
//service B
CompletableFuture<ServiceBResponse> serviceBFuture = CompletableFuture.supplyAsync(
() -> this.ServiceB.retrieve(serviceBRequest), serviceBExecutorService
);
CompletableFuture.allOf(serviceAFuture, serviceBFuture).join();
ServiceAResponse responseA = serviceAFuture.join();
ServiceBResponse responseB = serviceBFuture.join();
执行器服务和服务响应正在模拟,但测试从未结束,线程一直在这一行等待
CompletableFuture.allOf(serviceAFuture, serviceBFuture).join();
有没有关于我这里遗漏了什么的线索?谢谢大家! 如果我是您,我会简单地模拟服务A和B以及您的执行者,然后通过注释注入它们,因为它们是类的字段 如果您想模拟
执行器的执行
方法,您应该继续执行下一步,只需调用提供的可运行
的运行
:
doAnswer(
(InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}
).when(serviceAExecutorService).execute(any(Runnable.class));
所以基本上你的测试是这样的:
@RunWith(MockitoJUnitRunner.class)
public class CompletableFutureServiceTest {
// The mock of my service A
@Mock
private ServiceA ServiceA;
// The mock of my service B
@Mock
private ServiceB ServiceB;
// The mock of your executor for the service A
@Mock
private Executor serviceAExecutorService;
// The mock of your executor for the service B
@Mock
private Executor serviceBExecutorService;
// My class in which I want to inject the mocks
@InjectMocks
private CompletableFutureService service;
@Test
public void testSomeMethod() {
// Mock the method execute to call the run method of the provided Runnable
doAnswer(
(InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}
).when(serviceAExecutorService).execute(any(Runnable.class));
doAnswer(
(InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}
).when(serviceBExecutorService).execute(any(Runnable.class));
ServiceAResponse serviceAResponse = ... // The answer to return by service A
// Make the mock of my service A return my answer
when(ServiceA.retrieve(any(ServiceARequest.class))).thenReturn(
serviceAResponse
);
ServiceBResponse serviceBResponse = ... // The answer to return by service B
// Make the mock of my service B return my answer
when(ServiceB.retrieve(any(ServiceBRequest.class))).thenReturn(
serviceBResponse
);
// Execute my method
ServiceResponse response = service.someMethod(
new ServiceARequest(), new ServiceBRequest()
);
// Test the result assuming that both responses are wrapped into a POJO
Assert.assertEquals(serviceAResponse, response.getServiceAResponse());
Assert.assertEquals(serviceBResponse, response.getServiceBResponse());
}
}
@Mock
专用异步执行器异步执行器;
@嘲弄
私有完整未来XYZ样本响应;
@嘲弄
私人完整的未来ABC样本响应;
@以前
public void setUp()引发异常{
ABCSamplerResponse=CompletableFuture.completedFuture(TestUtil.readJsonResource(
“misc_mapper_response.json”,新类型引用(){
}));
xyzSampleResponse=CompletableFuture.completedFuture(TestUtil.readJsonResource(
“gp_facade_response.json”,新类型引用(){
}));
}
@试验
公共方法(){
Mockito.doReturn(ABCSamplerResponse).when(asyncExecuter)
.callPgEndpoint(TestConstants.TEST_CUSTOMER_ID);
Mockito.doReturn(xyzSampleResponse).when(asyncExecuter)
.getUserPreference(TestConstants.TEST\u CUSTOMER\u ID);
最终实际响应实际响应=全局位置服务
.getGlobalPosition(TestConstants.TEST\u CUSTOMER\u ID);
assertNotNull(实际响应);
}
====服务
公共实际响应getGlobalPosition(最终字符串customerId){
最终可完成未来ABCSamplerResponse=asyncExecuter
.getProductTypeInfo();
最终CompletableFuture XYZSamplerResponse=asyncExecuter
.getUserPreference(customerId);
试一试{
返回新的ResponseDecorator(pgResponse.get(),userPreferenceResponse.get(),
productTypeInfo.get()).decoration();
}捕获(最终异常e){
log.error(“生成响应时发生错误”,e);
}
返回null;
}
@组成部分
公共类异步执行器{
public CompletableFuture callPgEndpoint(最终字符串customerId){
返回CompletableFuture.completedFuture(xxx);
}
}
这样做会得到NPE,因为我必须模拟我的Executor服务(我使用的是定制服务),但如果我使用的是moked服务,测试永远不会结束。当然,如果我使用默认的executor服务,而不将我的服务发送到CompletableFuture.SupplySync(),它的工作方式就像一个符咒。是的!非常感谢。这就是我一直要做的我想模拟ExecutionService.execute()方法?这正是我想做的,但在某种程度上它是有效的。
@RunWith(MockitoJUnitRunner.class)
public class CompletableFutureServiceTest {
// The mock of my service A
@Mock
private ServiceA ServiceA;
// The mock of my service B
@Mock
private ServiceB ServiceB;
// The mock of your executor for the service A
@Mock
private Executor serviceAExecutorService;
// The mock of your executor for the service B
@Mock
private Executor serviceBExecutorService;
// My class in which I want to inject the mocks
@InjectMocks
private CompletableFutureService service;
@Test
public void testSomeMethod() {
// Mock the method execute to call the run method of the provided Runnable
doAnswer(
(InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}
).when(serviceAExecutorService).execute(any(Runnable.class));
doAnswer(
(InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}
).when(serviceBExecutorService).execute(any(Runnable.class));
ServiceAResponse serviceAResponse = ... // The answer to return by service A
// Make the mock of my service A return my answer
when(ServiceA.retrieve(any(ServiceARequest.class))).thenReturn(
serviceAResponse
);
ServiceBResponse serviceBResponse = ... // The answer to return by service B
// Make the mock of my service B return my answer
when(ServiceB.retrieve(any(ServiceBRequest.class))).thenReturn(
serviceBResponse
);
// Execute my method
ServiceResponse response = service.someMethod(
new ServiceARequest(), new ServiceBRequest()
);
// Test the result assuming that both responses are wrapped into a POJO
Assert.assertEquals(serviceAResponse, response.getServiceAResponse());
Assert.assertEquals(serviceBResponse, response.getServiceBResponse());
}
}
@Mock
private AsyncExecuter asyncExecuter;
@Mock
private CompletableFuture<XyzSample> xyzSampleResponse;
@Mock
private CompletableFuture<Map<String, String>> abcSampleResponse;
@Before
public void setUp() throws Exception {
abcSampleResponse = CompletableFuture.completedFuture(TestUtil.readJsonResource(
"misc_mapper_response.json", new TypeReference<Map<String, String>>() {
}));
xyzSampleResponse = CompletableFuture.completedFuture(TestUtil.readJsonResource(
"gp_facade_response.json", new TypeReference<XyzSample>() {
}));
}
@Test
public void testAbcMethod() {
Mockito.doReturn(abcSampleResponse).when(asyncExecuter)
.callPgEndpoint(TestConstants.TEST_CUSTOMER_ID);
Mockito.doReturn(xyzSampleResponse).when(asyncExecuter)
.getUserPreference(TestConstants.TEST_CUSTOMER_ID);
final ActualResponse actualResponse = globalPositionService
.getGlobalPosition(TestConstants.TEST_CUSTOMER_ID);
assertNotNull(actualResponse);
}
=====Service
public ActualResponse getGlobalPosition(final String customerId) {
final CompletableFuture<Map<String, String>> abcSampleResponse = asyncExecuter
.getProductTypeInfo();
final CompletableFuture<XyzSample> xyzSampleResponse = asyncExecuter
.getUserPreference(customerId);
try {
return new ResponseDecorator(pgResponse.get(), userPreferenceResponse.get(),
productTypeInfo.get()).decorate();
} catch (final Exception e) {
log.error("Error Occurred while building the response", e);
}
return null;
}
@Component
public class AsyncExecuter {
public CompletableFuture<XyzSample> callPgEndpoint(final String customerId) {
return CompletableFuture.completedFuture(xxx);
}
}