首页 > 解决方案 > 模拟 LambdaClient 无法正常工作

问题描述

我正在尝试为下面的方法编写一个单元测试,它正在调用 Lambda。

import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.services.lambda.model.InvokeRequest;
import software.amazon.awssdk.services.lambda.model.InvokeResponse;

public class RoutingService {

  private LambdaClient lambdaClient;

  private String env;
  private String region;

  public RoutingService(){
     this.env = System.getenv(ENVIRONMENT);
     this.region = System.getenv(REGION);
     lambdaClient =  LambdaClient.builder().build();
  }

  public RoutingResponse invokeLambda(InvokeLambda request)  throws IOException {
    
    RoutingResponse invokeResponse = new RoutingResponse();

    String payload = createPayload(request);  // Some utility method
    String routingURI = getRoutingURI() ;  // Another utility method

    SDKBytes payloadBytes = SdkBytes.fromUtf8String(payload);

    InvokeRequest invokeRequest = InvokeRequest.builder()
                                  .functionName(routingUri)
                                  .payload(payloadBytes)
                                  .invocationType(INVOCATION_TYPE)   //  INVOCATION_TYPE  is caonstant = RequestResponse
                                  .build();

    try{
          InvokeResponse result;
          result = lambdaClient.invoke(invokeRequest);  //   Was trying to Mock this
          String resultString = result.payload().asUtf8String();
          invokeResponse = new ObjectMapper().readValue(resultString, RoutingResponse.class);
    }catch(AWSServiceExceptuion ex) {
          logger.error(new ErrorEvent(ex.awsErrorDetails.errorMessage(), ex.getMessage(), routingUri));
          invokeResponse.setStatusCode(ex.statusCode());
          invokeResponse.setBody(ex.getMessage());
    }

    return response;
 } 

我正在尝试为这种方法编写单元测试用例,如下所示(Mocking the LambdaClient)。
但它仍然试图调用 Lambda 客户端的调用方法。意味着 Mocking 无法正常工作。

public class RoutingServiceTest {

  @Mock
  private LambdaClient lambdaClient;

  @BeforeEach
  void setup(){
    MockitoAnnotations.initMocks(this);
  }

  @Test
  void invokeLambda() throws IOException, JSONException {

    Map<String,String> queryStringParameters = new HashMap<>();
    queryStringParameters.put("test","GOOG");

    String[] cookies = {"cookiea", "cookieb"};

    Map<String,String> headers = new HashMap<>();
    headers.put("header1","valuex");
    headers.put("header2","valuey");

    InvokeLambda fakeRequest = new InvokeLambda.InvokeLambdaBuilder()
                               .cdnToken("cdn-token").applicationName("eaf-4137-demo")
                               .service("quote").method("GET")
                               .path("QuoteService/getQuote")
                               .queryString(queryStringParameters)
                               .headers(headers)
                               .cookies(cookies)
                               .body("body")
                               .requestId("request-id")
                               .build();

      InvokeResponse fakeResponse = InvokeResponse.builder().build();  //  This class belongs to AWS library
      
      Mockito.when(lambdaClient.invoke(Mockito.any(InvokeRequest.class))).thenReturn(fakeResponse); //  This is not working correctly ..

      RoutingService routingService = new RoutingService();
      RoutingResponse response = routingService.invokeLambda(fakeRequest);

      Assertions.assertTrue(response.getStatusCode()==200);

   }
}

当我运行这个测试时,'RoutingService' 类的 try{} 块中抛出了一个异常,因为我们在 fakeResponse 中传递了一个虚拟的“cdn 令牌”。理想情况下,它不应该调用 lambda,因为我们正在模拟它。

请建议我在这里做错了什么?如何纠正这个?

标签: javaunit-testingaws-lambdamockitojunit5

解决方案


lambdaClient你的实例中没有你的模拟RoutingService。在死机中,您的模拟是在您的测试设置中创建的,但是您创建了一个新的 RoutingService 实例,它将创建自己的 lambdaClient 实例,而不是您在测试中创建的模拟。我建议更新您的 RoutingService 以允许构造函数依赖注入:

 public RoutingService(final LambdaClient lambdaClient){
     this.env = System.getenv(ENVIRONMENT);
     this.region = System.getenv(REGION);
     this.lambdaClient =  lambdaClient;
  }

并进行如下测试:

RoutingService routingService = new RoutingService(lambdaClient);
RoutingResponse response = routingService.invokeLambda(fakeRequest);

推荐阅读