

# C\# 中的 AWS Lambda 函数测试
<a name="dotnet-csharp-testing"></a>

**注意**  
有关测试无服务器解决方案的技术和最佳实践的完整介绍，请参阅[测试函数](testing-guide.md)一章。

 测试无服务器函数使用传统的测试类型和技术，但您还必须考虑对无服务器应用程序进行整体测试。基于云的测试将为您的函数和无服务器应用程序的质量提供**最准确**的衡量。

 无服务器应用程序架构包括可通过 API 调用提供关键应用程序功能的托管服务。因此，您的开发周期应包括在函数与服务交互时验证功能的自动化测试。

 如果您不创建基于云的测试，则可能会由于本地环境和已部署环境之间的差异而遇到问题。在将代码提升到下一个部署环境（例如 QA、暂存或生产）之前，您的持续集成过程应针对在云端预置的一套资源运行测试。

 继续阅读本简短指南，了解无服务器应用程序的测试策略，或者访问[无服务器测试示例存储库](https://github.com/aws-samples/serverless-test-samples)，深入了解特定于您所选语言和运行时系统的实用示例。

 ![illustration showing the relationship between types of tests](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/test-type-illustration2.png) 

 对于无服务器测试，您仍需要编写*单元*、*集成*和*端到端*测试。
+ **单元测试** – 针对隔离代码块运行的测试。例如，验证业务逻辑以计算给定特定项目和目的地的配送费用。
+ **集成测试** – 涉及通常在云环境中交互的两个或更多组件或服务的测试。例如，验证函数是否会处理队列中的事件。
+ **端到端测试** – 验证整个应用程序行为的测试。例如，确保正确设置基础设施，并确保事件在服务之间按预期流动，以记录客户的订单。

## 测试无服务器应用程序
<a name="dotnet-csharp-testing-techniques-for-serverless-applications"></a>

 您通常会使用多种方法来测试无服务器应用程序代码，包括在云端进行测试、使用 Mock 进行测试，以及偶尔使用仿真器进行测试。

### 在云端进行测试
<a name="dotnet-csharp-testing-in-the-cloud"></a>

 在云端进行测试对于各个阶段的测试（包括单元测试、集成测试和端到端测试）而言都很有价值。您可以针对部署在云端并与基于云的服务进行交互的代码运行测试。这种方法可以**准确**衡量代码的质量。

 在云端调试 Lambda 函数的一种便捷方法是在控制台中使用测试事件。*测试事件*是函数的一个 JSON 输入。如果函数不需要输入，则事件可以是空 JSON 文档 `({})`。控制台为各种服务集成提供示例事件。在控制台中创建事件后，您可以将其与团队共享，以简化测试并保持一致性。

**注意**  
[在控制台中测试函数](testing-functions.md)是一种快速开始的方法，但自动化测试周期可确保应用程序质量和开发速度。

### 测试工具
<a name="dotnet-csharp-testing-tools"></a>

为了加速开发周期，您可以在测试函数时使用多种工具和技术。例如，[AWS SAM Accelerate](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/using-sam-cli-sync.html) 和 [AWS CDK 监视模式](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-deploy-watch)都减少了更新云环境所需的时间。

您定义 Lambda 函数代码的方式使添加单元测试变得简单。Lambda 需要公共、无参数的构造函数来初始化您的类。引入第二个内部构造函数可以让您控制应用程序使用的依赖关系。

```
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace GetProductHandler;

public class Function
{
    private readonly IDatabaseRepository _repo;
    
    public Function(): this(null)
    {
    }
    
    internal Function(IDatabaseRepository repo)
    {
        this._repo = repo ?? new DatabaseRepository();
    }
    
    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request)
    {
        var id = request.PathParameters["id"];
        
        var databaseRecord = await this._repo.GetById(id);
        
        return new APIGatewayProxyResponse 
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = JsonSerializer.Serialize(databaseRecord)
        };
    }
}
```

要为此函数编写测试，您可以初始化 `Function` 类的新实例，然后传递 `IDatabaseRepository` 的模拟实现。以下示例使用 `XUnit`、`Moq` 和 `FluentAssertions` 来编写简单的测试，以确保 `FunctionHandler` 返回 200 状态代码。

```
using Xunit;
using Moq;
using FluentAssertions;

public class FunctionTests
{
    [Fact]
    public async Task TestLambdaHandler_WhenInputIsValid_ShouldReturn200StatusCode()
    {
        // Arrange
        var mockDatabaseRepository = new Mock<IDatabaseRepository>();
        
        var functionUnderTest = new Function(mockDatabaseRepository.Object);
        
        // Act
        var response = await functionUnderTest.FunctionHandler(new APIGatewayProxyRequest());
        
        // Assert
        response.StatusCode.Should().Be(200);
    }
}
```

有关更详细的示例，包括异步测试的示例，请参阅 GitHub 上的 [.NET 测试示例存储库](https://github.com/aws-samples/serverless-test-samples/tree/main/dotnet-test-samples)。