Java – Unit test with the final class of the AWS SDK

Unit test with the final class of the AWS SDK… here is a solution to the problem.

Unit test with the final class of the AWS SDK

I wrote the following code to publish some metrics about the AWS Step function (its AWS Java lambda).

@Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
    int inProgressStateMachines = 0;

LocalDateTime now = LocalDateTime.now();

long alarmThreshold = getAlarmThreshold(input, context.getLogger());

AWSStepFunctions awsStepFunctions = AWSStepFunctionsClientBuilder.standard().build();

ListStateMachinesRequest listStateMachinesRequest = new ListStateMachinesRequest();
    ListStateMachinesResult listStateMachinesResult = awsStepFunctions.listStateMachines(listStateMachinesRequest);

for (StateMachineListItem stateMachineListItem : listStateMachinesResult.getStateMachines()) {

ListExecutionsRequest listExecutionRequest = new ListExecutionsRequest()
                .withStateMachineArn(stateMachineListItem.getStateMachineArn())
                .withStatusFilter(ExecutionStatus.RUNNING);

ListExecutionsResult listExecutionsResult = awsStepFunctions.listExecutions(listExecutionRequest);

for (ExecutionListItem executionListItem : listExecutionsResult.getExecutions()) {

LocalDateTime stateMachineStartTime = LocalDateTime.ofInstant(
                    executionListItem.getStartDate().toInstant(), ZoneId.systemDefault());

long elapsedTime = ChronoUnit.SECONDS.between(stateMachineStartTime, now);

if (elapsedTime > alarmThreshold){
                inProgressStateMachines++;
            }
        }

publishMetrics(inProgressStateMachines);
    }
}

Now I’m trying to unit test the method and I’m running into some issues.

First, when I try to simulate AWSStepFunctionsClientBuilder, I get the error that Mockito can not mock the final class.

Second, I have private methods that are called with specific parameters.

The question is

  1. How do I unit test this code? I read somewhere that if the code is not unit testable, then it’s a bad design. How can I improve this code to make it easy to test? I prefer to leave these helper methods as private methods.

  2. How do I test this code by emulating the final object from the AWS SDK? I can’t use any other framework other than Mockito.

Solution

You don’t actually want to emulate AWSStepFunctionsClientBuilder because you’re actually calling AWSStepFunctions, and you still have to emulate it even after mocking the builder.

So let AWSStepFunctions be an instance variable:

// add appropriate getter/setter as well
private AWSStepFunctions awsStepFunctions;

Where the builder is currently called to initialize awsStepFunctions, change to:

if (awsStepFunctions == null)
    awsStepFunctions = AWSStepFunctionsClientBuilder.standard().build();

Now, during unit testing, you can set up awsStepFunctions to simulate an instance, bypassing the conditional initialization above.

[edit] More ideas based on @kdgregory comments below:

The answer above is to provide a solution in the case of an existing code structure without any major refactoring. But in general, ideally, you want to move most of your code to another simpler, more testable Java class where you can inject dependencies properly, manage lifecycles, and so on.

Related Problems and Solutions