跳转到正文
zeno's blog
返回

微服务(四):No-mock 趋势与测试策略

专题: 微服务

Table of contents

Open Table of contents

TL;DR

Clean Architecture 做对了的话,大部分层根本不需要 mock:domain 层零依赖直接测,repository 层必须用真实基础设施(testcontainers),use case 层视编排复杂度决定。Mock 只在外部不可控系统(支付网关、短信)和故障注入场景下合理。


分层看测试策略

需不需要 mock?为什么
Domain不需要,也没东西可 mock零依赖,纯函数/方法,直接调直接断言
Use Case视复杂度而定简单编排(validate → save)→ 直接集成测试;复杂编排(条件分支、多 repo 协调、补偿逻辑)→ mock repo 测所有路径更高效
Repository/Adapter必须用真实基础设施这里 mock 是最有害的——你测的是 SQL 对不对、mapping 对不对,mock 掉就等于没测
API 端到端真实请求 + 真实 DBtestcontainers 起 PostgreSQL,发真实 HTTP/gRPC 请求

为什么 mock 在 repository 层有害

// 用 mock 测试——永远不会失败,但生产环境 SQL 可能是错的
mockRepo.On("GetByID", 1).Return(&domain.User{Name: "test"}, nil)

// 用 testcontainers——SQL 真的跑了一遍,schema 不对立刻爆
func TestGetByID(t *testing.T) {
    ctx := context.Background()
    pg, _ := postgres.Run(ctx, "postgres:16",
        postgres.WithDatabase("test"),
        postgres.WithInitScripts("schema.sql"),
    )
    defer pg.Terminate(ctx)

    db := connectTo(pg)
    repo := NewPostgresUserRepo(gen.New(db))

    user, err := repo.GetByID(1)
    // 这个测试真的验证了 SQL + mapping
}

Mock 测的是你对数据库行为的假设,不是数据库的真实行为。当假设和现实偏离(schema 迁移、字段类型变更、NULL 处理),mock 测试照样绿,生产炸了。

Clean Architecture 让 no-mock 更容易

反直觉的点:分层不是为了”每层都 mock”,而是为了让某些层不需要任何 test double

Domain 测试:   user.Validate() → 纯逻辑,不需要任何依赖
UseCase 测试:  注入真实 repo(testcontainers)→ 集成测试
API 测试:      真实 HTTP 请求 → 端到端测试

如果没有 Clean Architecture,业务逻辑和 SQL 混在 handler 里,你要么 mock 数据库测业务逻辑,要么每个测试都起数据库——前者不靠谱,后者太慢。分层之后,domain 测试不需要数据库,集成测试才需要。

什么时候 mock 仍然合理

原则:mock 外部系统的不可控行为,不 mock 你自己的代码。


分享这篇文章:

上一篇
axum(一):设计哲学-类型驱动的零成本 Web 框架
下一篇
微服务(三):多实例共享数据库为什么不需要额外同步