无法使用 Mockito 在 Spring 引导中模拟 AWSSecretsManager

Unable to mock AWSSecretsManager in Spring boot using Mockito

我是 Java 的新手,我已经创建了示例 class,我需要为其编写单元测试用例

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;
        }
    }
}

我尝试编写如下单元测试用例

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"));
    }
}

但是我的测试失败了,它说 AWSSecretsManager 为 null 并出现以下错误。

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

我尝试了不同的解决方案,但无法帮助我成功执行测试用例。

我认为你是如何构建代码的,这使得注入 AWSSecretsManager 客户端变得非常困难。这是因为它没有作为 MySecretService 服务中的依赖项公开。

我建议做的是:

  1. 创建配置 class 并将 AWSSecretsManager 的实例放入 IoC 容器中:
@Configuration
public class AWSConfig {
    @Bean
    public AWSSecretsManager awsSecretsManager() {
        return AWSSecretsManagerClientBuilder.standard()
                .withRegion("us-east-1")
                .build();
    }
}
  1. 在您的服务中注入 AWSSecretsManager 的 bean:
@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. 现在,在您的测试中,我发现您正在混合使用 JUnit 4 和 Junit 5 依赖项,这不是一个好主意。最新的 Spring 用于测试的引导启动程序随 JUnit 5 一起提供,我建议坚持使用它。知道了这一点,我们可以做到以下几点:
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"));
    }
}