第 13 章 C#测试与Docker部署

13.1 单元测试与集成测试

单元测试:测试单个组件(如服务方法),隔离外部依赖(用 Moq 模拟),使用 xUnit 框架。

实战案例:单元测试 UserService

  1. 创建单元测试项目:Visual Studio 新建 “xUnit 测试项目”,安装 NuGet 包:xunit、xunit.runner.visualstudio、Moq、Microsoft.EntityFrameworkCore。
  2. 编写单元测试
public class UserServiceTests
{
    private readonly Mock<AppDbContext> _mockDbContext;
    private readonly IUserService _userService;

    // 测试初始化(每个测试方法前执行)
    public UserServiceTests()
    {
        // 1. 模拟DbContext和DbSet
        var userData = new List<User>
        {
            new User { Id = 1, Name = "张三", Email = "zhangsan@test.com", Age = 25 },
            new User { Id = 2, Name = "李四", Email = "lisi@test.com", Age = 30 }
        }.AsQueryable();

        var mockDbSet = new Mock<DbSet<User>>();
        mockDbSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(userData.Provider);
        mockDbSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(userData.Expression);
        mockDbSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(userData.ElementType);
        mockDbSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(userData.GetEnumerator());

        // 2. 模拟DbContext
        _mockDbContext = new Mock<AppDbContext>();
        _mockDbContext.Setup(m => m.Users).Returns(mockDbSet.Object);

        // 3. 注入模拟的DbContext到UserService
        _userService = new UserService(_mockDbContext.Object);
    }

    // 测试1:GetUserNameByIdAsync返回正确姓名
    [Fact]
    public async Task GetUserNameByIdAsync_ExistingId_ReturnsCorrectName()
    {
        // Arrange:准备测试数据(已在构造函数中完成)
        int userId = 1;
        string expectedName = "张三";

        // Act:执行待测试方法
        var actualName = await _userService.GetUserNameByIdAsync(userId);

        // Assert:验证结果
        Assert.Equal(expectedName, actualName);
    }

    // 测试2:GetUserNameByIdAsync返回未知用户
    [Fact]
    public async Task GetUserNameByIdAsync_NonExistingId_ReturnsUnknown()
    {
        // Arrange
        int userId = 99;
        string expectedName = "未知用户";

        // Act
        var actualName = await _userService.GetUserNameByIdAsync(userId);

        // Assert
        Assert.Equal(expectedName, actualName);
    }
}
    1. 运行测试:Visual Studio 测试资源管理器→运行所有测试,查看结果。

13.2 API 测试工具与自动化

  • Postman:手动测试 API,支持保存测试用例、环境变量。
  • 自动化 API 测试:用 xUnit+HttpClient 测试 API 端点,示例:
public class UserApiTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;

    // 集成测试:使用WebApplicationFactory创建测试服务器
    public UserApiTests(WebApplicationFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    // 测试GET /api/v1/users
    [Fact]
    public async Task GetUsers_ReturnsSuccess()
    {
        // Act
        var response = await _client.GetAsync("/api/v1/users?page=1&pageSize=10");

        // Assert
        response.EnsureSuccessStatusCode(); // 验证状态码200
        var responseBody = await response.Content.ReadFromJsonAsync<PagedResult<UserDto>>();
        Assert.NotNull(responseBody);
        Assert.True(responseBody.Total >= 0);
    }

    // 测试POST /api/v1/users(需先登录获取Token)
    [Fact]
    public async Task CreateUser_ReturnsCreated()
    {
        // 1. 先登录获取Token
        var loginRequest = new LoginRequest { UserName = "admin", Password = "123456" };
        var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", loginRequest);
        loginResponse.EnsureSuccessStatusCode();
        var loginResult = await loginResponse.Content.ReadFromJsonAsync<dynamic>();
        string token = loginResult.Token;

        // 2. 添加Token到请求头
        _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // 3. 测试创建用户
        var createRequest = new CreateUserRequest { Name = "王五", Email = "wangwu@test.com", Age = 28 };
        var response = await _client.PostAsJsonAsync("/api/v1/users", createRequest);

        // 4. 验证结果
        Assert.Equal(HttpStatusCode.Created, response.StatusCode);
        var user = await response.Content.ReadFromJsonAsync<UserDto>();
        Assert.Equal(createRequest.Name, user.Name);
    }
}

13.3 容器化部署与 Docker

  • Docker 部署流程:编写 Dockerfile→构建镜像→运行容器。
  • 实战案例:Docker 部署ASP.NET Core API
  • 编写 Dockerfile(项目根目录):
# 阶段1:构建应用(使用SDK镜像)
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# 复制项目文件
COPY ["MyWebApi.csproj", "."]
# 还原依赖
RUN dotnet restore "MyWebApi.csproj"
# 复制所有文件
COPY . .
# 构建发布版本
RUN dotnet build "MyWebApi.csproj" -c Release -o /app/build
RUN dotnet publish "MyWebApi.csproj" -c Release -o /app/publish /p:UseAppHost=false

# 阶段2:运行应用(使用 runtime 镜像,体积更小)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
# 从构建阶段复制发布文件
COPY --from=build /app/publish .
# 设置环境变量(生产环境)
ENV ASPNETCORE_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=http://+:80
# 暴露端口
EXPOSE 80
# 启动应用
ENTRYPOINT ["dotnet", "MyWebApi.dll"]
  • 构建 Docker 镜像bash
docker build -t mywebapi:v1  .
  • 运行 Docker 容器bash
# 映射主机端口8080到容器端口80,挂载配置文件(可选)
docker run -d -p 8080:80 --name mywebapi-container mywebapi:v1
  • 测试访问:访问http://localhost:8080/api/v1/users,或http://localhost:8080/swagger。
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 共1条

请登录后发表评论