Reputation: 8704
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
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.
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
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