.NET 测试、发布与 Docker 部署入门

系统讲解 .NET 项目的测试基础、xUnit、集成验证、发布流程与 Docker 部署入门。

.NET 测试、发布与 Docker 部署入门

很多学习 .NET 的同学在前半段会把主要精力放在语言、Web API 和数据库上,但如果你的目标是真正交付一个项目,那么测试和部署一定要补上。

因为一个项目不是“本地能跑起来”就结束了,你还需要回答这些问题:

  • 代码改了之后怎么验证没有把旧功能带坏?
  • 接口项目如何生成发布产物?
  • 怎样把项目放进 Docker 容器里运行?
  • 线上配置和本地配置怎么区分?

这篇文章的目标,就是帮你把 .NET 项目从“开发态”推进到“可交付态”。


第一章 为什么测试和部署必须单独学习

只会写功能代码,但不会验证和交付,项目就很难真正落地。

测试解决的是:

  • 功能是否正确
  • 改动有没有回归风险

部署解决的是:

  • 项目怎么运行到目标环境
  • 配置如何切换
  • 产物如何组织

这两块补齐后,你才算对一个后端项目有完整认知。


第二章 .NET 项目里常见的测试类型

2.1 单元测试

关注单个类、单个方法的行为是否符合预期。

特点:

  • 运行快
  • 定位问题明确
  • 通常不依赖数据库和外部服务

2.2 集成测试

关注多个组件协作是否正常。

例如:

  • 控制器 + 服务 + 数据访问一起工作是否正确
  • HTTP 接口返回是否符合预期

2.3 端到端验证

更贴近真实运行路径,但成本也更高。

入门阶段不用一开始就把自动化测试铺得特别满,但至少要建立:

  • 单元测试意识
  • 接口集成验证意识

第三章 使用 xUnit 创建测试项目

3.1 创建测试项目

dotnet new xunit -n Demo.Tests

3.2 把测试项目加入解决方案

dotnet sln add .\Demo.Tests\Demo.Tests.csproj

3.3 添加业务项目引用

dotnet add .\Demo.Tests\Demo.Tests.csproj reference .\src\Demo.Application\Demo.Application.csproj

第四章 第一个单元测试

先有一个简单类:

public class PriceCalculator
{
    public decimal Calculate(decimal price, int count)
    {
        return price * count;
    }
}

测试代码:

using Xunit;

public class PriceCalculatorTests
{
    [Fact]
    public void Calculate_Should_Return_TotalPrice()
    {
        var calculator = new PriceCalculator();

        var result = calculator.Calculate(10m, 3);

        Assert.Equal(30m, result);
    }
}

4.1 [Fact] 是什么

[Fact] 表示一个普通测试用例。

如果要做参数化测试,可以使用 [Theory]


第五章 参数化测试

5.1 示例

using Xunit;

public class MathService
{
    public int Add(int a, int b) => a + b;
}

public class MathServiceTests
{
    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(5, 6, 11)]
    [InlineData(-1, 1, 0)]
    public void Add_Should_Return_Expected_Result(int a, int b, int expected)
    {
        var service = new MathService();

        var result = service.Add(a, b);

        Assert.Equal(expected, result);
    }
}

5.2 什么时候用 [Theory]

适合:

  • 同一逻辑需要多组输入验证
  • 参数组合明确

第六章 什么样的代码值得写测试

不是所有代码都值得同样密度的测试。

更值得优先测试的通常是:

  • 业务规则
  • 金额计算
  • 状态流转
  • 权限判断
  • 参数转换

相对不那么值得写大量样板测试的通常是:

  • 纯数据搬运
  • 很薄的简单封装
  • 主要依赖框架行为的样板代码

测试的目标是降低回归风险,而不是为了“测试数量好看”。


第七章 测试时为什么要重视边界条件

很多 bug 不是出在正常路径,而是边界场景。

例如:

  • null
  • 空字符串
  • 零值
  • 重复数据
  • 超大值
  • 非法状态

一个业务方法即使正常输入没问题,也不代表边界场景没问题。


第八章 运行测试

命令行执行:

dotnet test

如果只运行指定项目:

dotnet test .\Demo.Tests\Demo.Tests.csproj

这一步最好形成习惯:

  • 改完代码先跑测试
  • 提交前至少跑一轮关键测试

第九章 Web API 项目如何做基础集成验证

即使不一开始就铺完整集成测试,也建议至少建立接口验证意识。

你可以通过这些方式做验证:

  • Swagger 手工验证
  • Postman / Apifox 验证
  • 自动化 HTTP 集成测试

入门阶段先至少做到:

  • 关键接口有可重复验证方式

第十章 .NET 项目如何发布

本地开发通常用:

dotnet run

但部署前通常要先生成发布产物:

dotnet publish -c Release -o .\publish

10.1 publishbuild 的区别

  • build:主要是编译
  • publish:用于生成可部署产物

发布目录里通常会包含:

  • 应用程序集
  • 依赖项
  • 配置文件
  • 运行所需资源

第十一章 发布前应该检查什么

发布不只是命令跑通,还要关注下面这些问题:

11.1 配置是否准备完整

例如:

  • 数据库连接串
  • JWT 配置
  • Redis 配置
  • 上传目录
  • 日志目录

11.2 环境变量是否正确

很多线上问题其实是环境没配对,不是代码问题。

11.3 数据库迁移是否已执行

如果项目依赖数据库结构变化,部署前要确认:

  • 迁移是否已准备
  • 目标环境是否已更新

第十二章 Docker 为什么适合部署 .NET 项目

Docker 的价值不是“更潮”,而是:

  • 运行环境更一致
  • 部署更标准化
  • 更适合服务器和容器环境

你可以把它理解成把应用及其运行环境一起打包。


第十三章 一个基础的 .NET Dockerfile

下面是一个典型的多阶段构建示例:

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

COPY . .
RUN dotnet restore
RUN dotnet publish ./src/Demo.Api/Demo.Api.csproj -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app

COPY --from=build /app/publish .

EXPOSE 8080

ENTRYPOINT ["dotnet", "Demo.Api.dll"]

13.1 这份 Dockerfile 的思路

第一阶段:

  • 使用 SDK 镜像
  • 恢复依赖
  • 编译并发布

第二阶段:

  • 使用更轻量的运行时镜像
  • 拷贝发布结果
  • 启动应用

这就是典型的多阶段构建思路。


第十四章 本地构建和运行 Docker 镜像

14.1 构建镜像

docker build -t demo-api:1.0 .

14.2 启动容器

docker run -d -p 8080:8080 --name demo-api demo-api:1.0

如果你的应用监听的是容器内 8080 端口,那么外部访问:

http://localhost:8080

第十五章 Docker 环境下配置怎么处理

容器部署时,通常不要把所有环境差异硬写进镜像。

更常见的方式是通过:

  • 环境变量
  • 挂载配置文件
  • 编排工具注入配置

例如设置环境:

docker run -d -p 8080:8080 `
  -e ASPNETCORE_ENVIRONMENT=Production `
  --name demo-api demo-api:1.0

这能让应用按生产环境配置运行。


第十六章 一个比较实用的发布流程认知

入门阶段可以先把发布流程理解成下面这条线:

写代码
-> 跑测试
-> dotnet publish
-> 生成部署产物
-> Docker 打包
-> 目标环境启动
-> 验证接口

先把这条线跑通,比一开始追求复杂 CI/CD 更重要。


第十七章 初学者常见坑

17.1 不写测试,只靠手点

项目越大,这种方式越不稳定。

17.2 发布前不检查环境配置

最常见的部署事故来源之一。

17.3 Dockerfile 能构建,但应用启动失败

通常要检查:

  • 入口 DLL 名字
  • 端口暴露
  • 环境变量
  • 配置文件

17.4 本地能跑,容器里不能跑

常见原因:

  • 路径依赖本地环境
  • 配置文件缺失
  • 端口映射错误
  • 外部依赖地址不可达

第十八章 入门阶段建议掌握到什么程度

建议至少做到:

  1. 会创建并运行 xUnit 测试项目
  2. 能写基础单元测试和参数化测试
  3. 知道哪些代码更值得优先测试
  4. 会使用 dotnet publish 生成发布产物
  5. 能看懂基础 Dockerfile
  6. 能完成一次最基本的容器化运行

延伸阅读

  • 如果你还没掌握 .NET 工程基础,先阅读 .NET CLI 与项目结构
  • 如果你想把日志和配置与部署串起来,继续阅读 .NET 配置、选项绑定与日志实践
  • 如果你想继续补齐接口层治理,继续阅读 ASP.NET Core 统一异常处理与统一返回

本文小结

测试和部署的意义,在于把项目从“开发环境里的代码”变成“可验证、可交付、可运行的系统”。对 .NET 开发者来说,哪怕不一开始就把自动化和容器体系做得很复杂,也应该先掌握这条最基础的交付主线:

  • 写完能测
  • 改动能验证
  • 程序能发布
  • 项目能容器化运行

这一步补齐后,你对整个 .NET 项目的理解才算真正完整。