Home > Net >  Unable to mock AWSSecretsManager in Spring boot using Mockito
Unable to mock AWSSecretsManager in Spring boot using Mockito

Time:12-26

I am new to Java and I have created sample class for which I need to write unit test case

import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
import com.amazonaws.services.secretsmanager.model.InvalidParameterException;
import com.amazonaws.services.secretsmanager.model.ResourceNotFoundException;
import org.springframework.stereotype.Component;

@Component
public class MySecretService {

    private AWSSecretsManager client;

    public MySecretService() {
        this.client = AWSSecretsManagerClientBuilder.standard().withRegion("US-west-2").build();
    }

    public String GetMyKey(String secretId) {
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
        getSecretValueRequest.setSecretId(secretId);
        try {
            GetSecretValueResult getSecretValueResult = client.getSecretValue(getSecretValueRequest);

            return getSecretValueResult.getSecretString();
        } catch (ResourceNotFoundException resourceNotFoundException) {
            throw resourceNotFoundException;
        } catch (InvalidParameterException invalidParameterException) {
            throw invalidParameterException;
        }
        catch (Exception ex)
        {
            throw  ex;
        }
    }
}

I tried to write unit test case as below

import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
import com.amazonaws.services.secretsmanager.model.ResourceNotFoundException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
class MySecretServiceTest {

    @Mock
    private AWSSecretsManager client;

    private MySecretService mySecretService;

    @BeforeEach
    void setUp() {
        this.mySecretService = new MySecretService();
    }

    @Test
    void getMyKey() {
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
        getSecretValueRequest.setSecretId("test");

        GetSecretValueResult getSecretValueResult = new GetSecretValueResult();
        getSecretValueResult.setSecretString("xyz");
        when(this.client.getSecretValue(getSecretValueRequest))
                .thenReturn( getSecretValueResult);

        assertEquals("xyz", mySecretService.GetMyKey("test"));
    }
}

However my test is getting failed where it says AWSSecretsManager is null with below error.

java.lang.NullPointerException at com.example.demo.MySecretServiceTest.getMyKey(MySecretServiceTest.java:40)

I tried different solution but won't help me to execute the test cases successfully.

CodePudding user response:

I think that way how did you structure your code, you make it really hard to inject AWSSecretsManager client. This is because it is not exposed as a dependency in the MySecretService service.

What I suggest doing is the following:

  1. Create a configuration class and put an instance for AWSSecretsManager in the IoC container:
@Configuration
public class AWSConfig {
    @Bean
    public AWSSecretsManager awsSecretsManager() {
        return AWSSecretsManagerClientBuilder.standard()
                .withRegion("us-east-1")
                .build();
    }
}
  1. Inject the bean of AWSSecretsManager inside your service:
@Service
public class MySecretService {
    private final AWSSecretsManager awsSecretsManager;

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

    public String getMyKey(String secretId) {
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest().withSecretId(secretId);
        try {
            GetSecretValueResult getSecretValueResult = awsSecretsManager.getSecretValue(getSecretValueRequest);
            return getSecretValueResult.getSecretString();
        } catch (ResourceNotFoundException | InvalidParameterException resourceNotFoundException) {
            throw resourceNotFoundException;
        }
    }
}
  1. Now, in your test I see that you are mixing JUnit 4 and Junit 5 dependencies, which is not a good idea. The latest Spring Boot starter for testing comes with JUnit 5, I suggest sticking to it. Knowing this, we can do the following:
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.model.GetSecretValueRequest;
import com.amazonaws.services.secretsmanager.model.GetSecretValueResult;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class MySecretServiceTest {

    @Mock
    private AWSSecretsManager client;

    @InjectMocks
    private SecretsService mySecretService;

    @Test
    void getMyKey() {
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
        getSecretValueRequest.setSecretId("test");

        GetSecretValueResult getSecretValueResult = new GetSecretValueResult();
        getSecretValueResult.setSecretString("xyz");
        when(client.getSecretValue(getSecretValueRequest))
                .thenReturn(getSecretValueResult);

        assertEquals("xyz", mySecretService.GetMyKey("test"));
    }
}
  • Related