C# 架构精通 — 清洁架构中的测试策略 (.NET) (第7部分)
发布: (2025年12月24日 GMT+8 04:57)
4 min read
原文: Dev.to
Source: Dev.to
你在测试什么
传统系统从外部向内部测试。
Clean Architecture 从内部向外部测试。
优先级顺序
- 领域逻辑
- 应用用例
- 基础设施集成
- Web / API 层
这种排序是有意为之。
经典测试金字塔
- 单元测试(大量)
- 集成测试(部分)
- 端到端测试(少量)
Clean Architecture 对其的优化
| 层 | 覆盖度 |
|---|---|
| 领域测试 | ███████████ |
| 应用测试 | ████████ |
| 集成测试 | ████ |
| API / E2E 测试 | ██ |
业务规则需要最高的信心。
业务规则
- 不变量
- 计算
- 状态转换
领域单元测试
// ✅ Domain unit test
[Fact]
public void Order_Cannot_Be_Created_With_Negative_Total()
{
var act = () => new Order(-10);
act.Should().Throw();
}
如果领域测试需要 mock,说明有问题。
带 mock 的应用测试
// ✅ Application test with mocks
[Fact]
public async Task CreateOrder_Saves_Order_And_Sends_Notification()
{
var repo = Substitute.For<IOrderRepository>();
var notifier = Substitute.For<INotifier>();
var useCase = new CreateOrderUseCase(repo, notifier);
await useCase.Execute(new CreateOrderCommand(100));
await repo.Received(1).SaveAsync(Arg.Any<Order>());
await notifier.Received(1).NotifyAsync(Arg.Any<Notification>());
}
Mock 只应出现在边界处。
基础设施测试
基础设施测试回答:“这个东西真的能工作吗?”
- EF Core 映射
- SQL 查询
- 外部 API
- 文件系统
- 消息中间件
EF Core 集成测试
// ✅ EF Core integration test
using var db = CreateRealDbContext();
var repo = new OrderRepository(db);
await repo.SaveAsync(order);
var saved = await db.Orders.FindAsync(order.Id);
saved.Should().NotBeNull();
这些测试更慢、数量更少,但却是必不可少的。
API 测试
API 测试应验证:
- 路由
- HTTP 合约
- 序列化
- 身份验证 / 授权
它们 不应 重新测试业务规则。
// ✅ API test
var response = await client.PostAsJsonAsync("/orders", request);
response.StatusCode.Should().Be(HttpStatusCode.OK);
如果 API 测试很复杂,说明控制器可能太臃肿。
不要测试
- 框架内部实现
- EF Core 本身
- ASP.NET Core 路由逻辑
- Microsoft 库
测试你的代码,而不是它们的代码。
警示信号
- 到处 mock
DbContext - 用集成测试取代单元测试
- 测试耦合到 HTTP 模型
- 重构时测试会失效
- 大量的测试初始化代码
这些通常表明边界被破坏。
测试不是为了覆盖率
测试是为了:
- 信心
- 变更安全性
- 设计反馈
好的测试让重构变得无聊。
上线前自问
- 业务规则是否在没有基础设施的情况下得到测试?
- 用例是否有聚焦的单元测试?
- 集成是否针对真实系统进行测试?
- API 测试是否简洁?
- 测试是否指导了设计决策?
如果答案是肯定的,你的架构就起作用了。
如果测试让人痛苦
- 重新审视边界
- 消除泄漏
- 简化职责
优秀的测试是优秀架构的副产品。