[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2216?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17539949#comment-17539949
 ] 

Oleg Kalnichevski commented on HTTPCLIENT-2216:
-----------------------------------------------

[~dkrompet] I do not understand the issue. You should be mocking / injecting 
`HttpAsyncClient` not `CloseableHttpAsyncClient`. 
Client services should be using `HttpAsyncClient` not 
`CloseableHttpAsyncClient`. 

Oleg

> ClosableHttpAsyncClient interface and testing
> ---------------------------------------------
>
>                 Key: HTTPCLIENT-2216
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2216
>             Project: HttpComponents HttpClient
>          Issue Type: Improvement
>          Components: HttpClient (async)
>    Affects Versions: 5.0
>            Reporter: Dillon Krompetz
>            Priority: Minor
>
> TLDR: Please insert interface that contains functionality of 
> CloseableHttpAsyncClient so that this can be tested more easily.
> ===========
> The current CloseableHttpAsyncClient implementation currently has a problem 
> in its interface and intended usage such that testing becomes more difficult 
> than it needs to be.
>  
> Class in question
> {code:java}
> public abstract class CloseableHttpAsyncClient implements HttpAsyncClient, 
> ModalCloseable {code}
>  
> Methods in question
> {code:java}
> public abstract void start(); {code}
> defined in CloseableHttpAsyncClient class
>  
> {code:java}
> <T> Future<T> execute(
>   AsyncRequestProducer requestProducer,
>   AsyncResponseConsumer<T> responseConsumer,
>   HandlerFactory<AsyncPushConsumer> pushHandlerFactory,
>   HttpContext context,
>   FutureCallback<T> callback
> ); {code}
> defined in HttpAsyncClient interface
>  
> {code:java}
> void close(CloseMode closeMode); {code}
> defined in ModalCloseable interface
>  
> How is this an issue?
> When a developer goes to make use of the Http5 async client they may follow 
> the guides provided: 
> [https://hc.apache.org/httpcomponents-client-5.1.x/examples-async.html] and 
> see that they need access to the above three methods.
>  
> They may introduce an adapter around this interface to take thier business 
> logic and convert it into an Http request compatable with the client.
>  
> {code:java}
> class MyHttp5AsyncClient {
>   private CloseableHttpAsyncClient client;
>  
>   public MyHttp5AsyncClient(CloseableHttpAsyncClient httpAsyncClient) {
>     this.client = httpAsyncClient;
>   }
>  
>   public start() {
>     this.client.start();
>   }
>  
>   public stop() {
>     this.client.close();
>   }
>  
>   public execute(MyRequest request) {
>     AsyncRequestProducer requestProducer = toRequestProducer(request);
>     Future<SimpelHttpResponse> result = client.execute(
>       requestProdcuer,
>       SimpleResponseConsumer.create(),
>       null,
>       null,
>       null
>     );
>     return result.get();
>   }
> } {code}
>  
> Note that in the CloseableHttpAsyncClient implementation that the execute 
> method is final:
> {code:java}
> public final <T> Future<T> execute(
>   final HttpHost target,
>   final AsyncRequestProducer requestProducer,
>   final AsyncResponseConsumer<T> responseConsumer,
>   final HandlerFactory<AsyncPushConsumer> pushHandlerFactory,
>   final HttpContext context,
>   final FutureCallback<T> callback) {
>     Args.notNull(requestProducer, "Request producer");
>     Args.notNull(responseConsumer, "Response consumer");
>     return doExecute(target, requestProducer, responseConsumer, 
> pushHandlerFactory, context, callback);
> } {code}
>  
> Testing
> Popular testing patterns include injecting the dependency into the class to 
> verify that methods were called with certain arguments or to mock the result 
> of calling a method to control the code flow in isolation. A very popular 
> Java mocking and verifying library might be Mockito where a developer may 
> write something like:
> {code:java}
> class MyHttp5AsyncClientTest {
>  
> @Mock
> private CloseableHttpAsyncClient client;
>  
> private MyHttp5AsyncClient toTest;
>  
> @BeforeEach
> public void setup() {
>   toTest = new MyHttp5AsyncClient(client);
> }
>  
> @Test
> public void execute_whenCalledWithSomeInput_thenWillDoTheThing() {
>   when(client.execute(
>     any(AsyncRequestProducer.class),
>     any(AsyncResponseConsumer.class),
>     nullable(HandlerFactory.class),
>     nullable(HttpContext.class),
>     nullable(FutureCallback.class)
>   )).thenReturn(
>     CompletableFuture.completedFuture(null)
>   );
>  
>   var result = toTest.execute(null);
>   // ...
>   // some expectations on the result that are interesting.
>  }
> } {code}
> This test will fail because the hard implementation of 
> CloseableHttpAsyncClient execute is final and when mocking it will call the 
> actual method with the result of calls to Mockito's any() which returns 
> nulls. This will then be caught by the guard statements in the actual method 
> call to execute.
>  
> How can this be made better?
> How I got around the issue:
> Inserted a wrapper around CloseableHttpAsyncClient that had the public 
> methods I needed to use that could be mocked.
>  
> How might this be better resolved:
> 1. Remove final modifier from the CloseableHttpAsyncClient methods that are 
> likely to be mocked.
> There is likely a reason these methods were intended to not be open for 
> modification :)
>  
> 2. Insert an interface that CloseableHttpAsyncClient implements that captures 
> its intended functionality.
> This new interface would include the public methods of 
> CloseableHttpAsyncClient and extend the interfaces for HttpAsyncClient and 
> ModalCloseable



--
This message was sent by Atlassian Jira
(v8.20.7#820007)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@hc.apache.org
For additional commands, e-mail: dev-h...@hc.apache.org

Reply via email to