Em Ae
Em Ae

Reputation: 8704

Unit testing with final classes of AWS SDK

I have written following code to publish some metrics around AWS Step function (its java lambda for aws)

@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 am trying to unit-test this method and having some issues.

First of all, I get error that Mockito can not mock final class when i tried to mock AWSStepFunctionsClientBuilder.

Secondly, I have private methods which are being called with specific params.

The question is

  1. How can i unit test this code? I read it somewhere that if a code isn't unit-testable then its a bad design. How can i improve this code so that its easily testable? I would prefer to keep those helper methods as private methods.

  2. How can i mock final objects from AWS SDK to test this code? I can not use any other framework but Mockito.

Upvotes: 3

Views: 2179

Answers (1)

jingx
jingx

Reputation: 4014

You actually don't want to mock AWSStepFunctionsClientBuilder because you are actually calling AWSStepFunctions, which you'll have to mock anyway even after mocking the builder.

So make AWSStepFunctions an instance variable:

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

Where you currently call the builder to initialize awsStepFunctions, change to:

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

Now, during unit test, you can set awsStepFunctions to a mocked instance, bypassing the conditional initialization above.

[Edit] Some more thoughts based on @kdgregory's comment below:

The answer above is meant to provide a solution given the existing code structure, without requiring any major refactoring. In general though, ideally you would want to move the bulk of the code into another plain, more testable Java class, where you can properly inject dependencies, manage life cycles, etc.

Upvotes: 3

Related Questions