Getting a Null response for AWSSecretsManager's getSecret while Mocking

Viewed 29

The Testcase I'm writing looks something like this

@Mock AWSClient awsClient;
@Mock AWSSecretsManager secretsManagerClient;
@Mock GetSecretValueResult secretValueResult;

private static final SECRET_VALUE = "value";
private static final ID = "id";

@Test
public void handleRequest() {

    when(secretsManagerClient.getSecretValue(any(GetSecretValueRequest.class))).thenReturn(secretValueResult);
    when(secretValueResult.getSecretString()).thenReturn(SECRET_VALUE));
    String response = awsClient.getSecretsManagerSecret(ID);
    assertNotNull(response);
}

The method I'm trying to test looks something like this (removed some try catch blocks and some logs) :

public class AWSClient{

    public String getSecretsManagerSecret(String id) {
        AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().build();
        GetSecretValueRequest request = new GetSecretValueRequest().withSecretId(id);
        GetSecretValueResult result = null;
        
        result = client.getSecretValue(request);
        response = result.getSecretString();

        return response;
    }
}

I am probably wrong about the functionality of the Secrets Manager Client here, but can anyone direct me towards why I'm getting a null response for the test? The when(secretValueResult.getSecretString()).thenReturn(SECRET_VALUE)); doesn't seem to work here as result.getSecretString() seems to return null. I need to mock the AWSClient as there are a few other external dependencies in that class and I don't have admin rights to install aws-cli.

Thanks in advance!

1 Answers

It is because you are actually using a real AWSSecretsManager and not the mocked version since this line AWSSecretsManager client = AWSSecretsManagerClientBuilder.standard().build(); is creating a new AWSSecretsManager so you will never get your mocked response back since that mock is not used.

Maybe consider to refactor the code so you don't need to Mock your class under test (AWSClient). A different approach then would be to inject the AWSSecretsManager and so you can mock it, example:

  private final AWSSecretsManager awsSecretsManager;

  public AWSClient(AWSSecretsManager awsSecretsManager) {
    this.awsSecretsManager = awsSecretsManager;
  }

  public String getSecretsManagerSecret(String id) {
    return awsSecretsManager
        .getSecretValue(new GetSecretValueRequest().withSecretId(id))
        .getSecretString();
  }

And refactor the test to inject the mock, example

  @Mock AWSSecretsManager secretsManager;

  @Test
  public void should_return_secret() {
    // given
    var secretValueResult = Mockito.mock(GetSecretValueResult.class);
        when(secretsManager.getSecretValue(any(GetSecretValueRequest.class)))
    .thenReturn(secretValueResult);
    when(secretValueResult.getSecretString()).thenReturn(SECRET_VALUE);

    // when
    var response = new AWSClient(secretsManager).getSecretsManagerSecret(ID);

    // then
    then(response).isEqualTo(SECRET_VALUE);
  }
Related