跳到主要内容

9.2 领域逻辑单元测试

单元测试最适合保护不依赖数据库、HTTP 和文件系统的业务规则。它运行快、定位准,是重构时最可靠的安全网。

学习目标

  • 能为实体和值对象编写单元测试。
  • 能用测试命名表达业务行为。
  • 能避免在单元测试中引入外部依赖。
  • 能区分单元测试和集成测试的边界。

应用场景

  • 任务标题不能为空。
  • 已完成任务不能重复完成或重复计数。
  • 优先级、截止日期和状态转换规则。
  • 价格、折扣、权限等纯业务计算。

示例:测试任务完成规则

public sealed class TodoItemTests
{
[Fact]
public void Complete_MarksTodoAsCompleted_WhenTodoIsOpen()
{
var todo = new TodoItem("学习单元测试");

todo.Complete(new DateTimeOffset(2026, 8, 12, 10, 0, 0, TimeSpan.Zero));

todo.IsCompleted.Should().BeTrue();
todo.CompletedAt.Should().NotBeNull();
}

[Fact]
public void Constructor_ThrowsException_WhenTitleIsEmpty()
{
var act = () => new TodoItem(" ");

act.Should().Throw<ArgumentException>()
.WithMessage("标题不能为空*");
}
}

测试命名建议

模式示例
方法_结果_条件Complete_MarksTodoAsCompleted_WhenTodoIsOpen
行为描述CannotCreateTodoWithoutTitle
业务规则描述CompletedTodoKeepsOriginalCompletedAt

重点难点

  • 单元测试不要连接真实数据库。
  • 测试应覆盖边界值,例如空标题、最大长度、重复操作。
  • 测试命名要让失败原因一眼可见。
  • 业务逻辑如果很难单元测试,通常说明依赖边界需要调整。

常见误区

误区推荐做法
只测试公共 API 成功路径核心业务失败路径也要测
一个测试断言过多行为一个测试聚焦一个业务事实
为了测试暴露大量 public set通过业务方法驱动状态变化

练习

  • TodoItem.Rename 写空标题和成功重命名测试。
  • 为“重复完成不改变 CompletedAt”写测试。
  • 把一个依赖系统时间的测试改为传入固定时间。

延伸阅读

  • xUnit。
  • FluentAssertions。
  • 测试金字塔。