title: Unit Testing on Java's ListenableFuture and the addListener callback
body: <p>I have a module that has a method which writes data to a Kinesis stream. We call it the Feedback stream.</p>
  
  <p>i want to run a verify unit test on my analytics service's functions that are invoked on ListenableFuture's result, i have tried setting up mocks but am getting a ClassCast exception. I think I may be setting up the mocks incorrectly.</p>
  
  <p>method i want to unit test:</p>
  
  <pre><code>public void writeData(KinesisRecord kinesisRecord, Response response) {
  
      FeedbackRecord feedbackRecord = new 
      FeedbackRecord(kinesisRecord.getVersion(), kinesisRecord.getNotificationId(), response.name(), 
  kinesisRecord.getDestination());
  
      Gson g = new Gson();
      byte[] dataBytes = g.toJson(feedbackRecord).getBytes(StandardCharsets.UTF_8);
      ListenableFuture&lt;UserRecordResult&gt; future = kinesisProducer.addUserRecord(streamName, kinesisRecord.getNotificationId(), ByteBuffer.wrap(dataBytes));
  
      future.addListener(() -&gt; {
      try {
          UserRecordResult userRecordResult = future.get();
          analyticsService.trackSuccess(AnalyticsConstants.FeedbackProducer.WRITE_SUCCESS, AnalyticsConstants.FeedbackProducer.WRITEDATA_LOCATION + " " + userRecordResult.getSequenceNumber());
          log.debug("Write to Kinesis Feedback successful, record sequence number: " + userRecordResult.getSequenceNumber());
      } catch (InterruptedException e) {
          e.printStackTrace();
          analyticsService.trackError(AnalyticsConstants.FeedbackProducer.WRITE_ERROR, AnalyticsConstants.FeedbackProducer.WRITEDATA_LOCATION);
          log.error("Feedback Kinesis Write failed: " + e);
      } catch (ExecutionException e) {
          e.printStackTrace();
          analyticsService.trackError(AnalyticsConstants.FeedbackProducer.WRITE_ERROR, AnalyticsConstants.FeedbackProducer.WRITEDATA_LOCATION);
          log.error("Feedback Kinesis Write failed: " + e);
      }
  }, MoreExecutors.directExecutor());
  </code></pre>
  
  <p>}
  unit test attempt:</p>
  
  <pre><code>@Test
  public void addUserRecordFutureTest() throws ExecutionException, InterruptedException {
  
      ListenableFuture&lt;UserRecordResult&gt; responseFuture = mock(ListenableFuture.class);
  
      Attempt attempt = new Attempt(1, 2, "AttemptError", "5xx", true);
      List&lt;Attempt&gt; attempts = new ArrayList&lt;&gt;();
      attempts.add(attempt);
      UserRecordResult mockUserRecordResult = mock(UserRecordResult.class);
  
      when(kinesisProducer.addUserRecord(any(), any(), any())).thenReturn(responseFuture);
      doAnswer(invocation -&gt; {
          ListenableFutureCallback listenableFutureCallback = invocation.getArgument(0);
          listenableFutureCallback.onSuccess(mockUserRecordResult);
      // do asserts here
          return null;
      }).when(responseFuture).addListener(any(), any());
  
      feedbackProducer.writeData(mockRecord, FeedbackProducer.Response.invalid_channel);
  }
  </code></pre>
  
  <p>STACK TRACE:</p>
  
  <p><a href="https://i.stack.imgur.com/q2cxE.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/q2cxE.png" alt="enter image description here"></a></p>