名词解释教学工作区 · 课程 0005 · 形态 单概念 · 约 5 分钟 · 前置:无 · 2026-10-01

测试夹具:先把前提摆成一样,再去看结果变没变

你能做到:看到「夹具」两个字时,先分清它指的是开跑前摆好的那套前提, 还是准备与恢复前提的那段代码;并且说清它和替身、测试数据、断言各自守哪一段。

1 | 定义

测试夹具(test fixture,简称 fixture): 跑一条测试之前,把被测对象摆进确定状态、跑完再恢复原状的那套准备与收尾;它管的是前提,本身不判对错。 就像每次开演前照同一张图把布景、灯光、道具摆好:桌子没挪地方,台上的差别才只能来自演员。

英文 fixture 借自机械加工 —— 把工件夹在确定位置,刀具走的路径才有意义;换到软件里, 就是先固定环境,再让被测代码去跑。准备那一步常叫 setup,恢复那一步常叫 teardown; 两者成对出现,才算一次完整的夹具。

2 | 它解决什么麻烦

一条测试本该只回答一个问题:换了被测代码,结果会不会跟着变。 麻烦在于,结果常常在代码一个字没改的情况下自己变。

三件事的根子是同一个:被测代码每次开跑时站在哪儿,得由你说了算。

3 | 它怎么解决

预置条件 setup 把状态摆到确定位置 -> 替身 test double 顶掉不受控的外部依赖 -> 测试数据 喂进去的原料 -> 被测代码 这一轮真正要验的东西 -> 断言 assertion 唯一说对与不对的一条 -> 收尾 teardown 恢复原状,别污染下一条

4 | 用它的代价

5 | 真实使用场景

场景一:用 pytest 的 fixture,给每条测试一条全新的内存库。

# conftest.py
import sqlite3, pytest

@pytest.fixture
def db():
    conn = sqlite3.connect(":memory:")        # 准备:每次一条全新的库
    conn.executescript(open("schema.sql").read())
    yield conn                                 # 交给测试用
    conn.close()                               # 收尾:跑完就丢

# tests/test_orders.py
def test_order_decrements_stock(db):
    ...

跑 python -m pytest -q:每条用到 db 的测试都自动走一遍「建库 -> 用 -> 关掉」, 不必在每条测试的开头再抄一遍建库代码。

场景二:JUnit 5 用注解把准备与收尾挂上。

class OrderServiceTest {
  private InMemoryOrderRepo repo;

  @BeforeEach void setUp()    { repo = new InMemoryOrderRepo(); }
  @AfterEach  void tearDown() { repo.close(); }
}

场景三:要验的确实是数据库本身,那就把真的数据库当夹具起起来。

docker run -d --rm -p 5432:5432 -e POSTGRES_PASSWORD=secret postgres:16

Testcontainers 这类库把上面这条命令包成一段代码:测试开跑时拉一个真的 PostgreSQL 容器、 结束就拆掉 —— 用的是真依赖,但起点每次一样,也不碰你本机那份数据。

6 | 和相近的东西怎么分

先问一句:它是前提,还是判据?摆前提、给原料、换依赖都只是前提,只有断言说「对 / 不对」。 前提里再分:整台机器开跑前的状态是夹具,某一个外部依赖是替身, 喂进去的原料是测试数据。

名词它是什么和测试夹具什么关系
测试夹具(test fixture) 开跑前把状态摆进确定位置、跑完再恢复的那套准备与收尾 本课主角:它管的是「每次从哪儿出发」
替身(test double / stub / fake / mock) 顶掉某一个外部依赖、替它上场应答的那件东西 常是夹具准备出来、再注入被测代码的一件东西:两者是嵌套,不是并列
测试数据(test data) 喂进被测代码的那批原料本身 原料不是机制:喂它的那套装置才叫夹具
断言(assertion) 唯一说「对 / 不对」的那一条声明 分工在时间上:夹具管开跑前,断言管开跑后
预置与收尾(setUp / tearDown) 夹具在代码里的两个挂点 两者成对才构成一次夹具:只写一半,等于半个夹具

一句话分工:夹具搭台,替身换角,数据当道具,断言才说这出戏演得对不对。

7 | 常见误解

8 | 练习

三题自测,每题只有一个正确选项;选完立刻看到解释。

1. 一条测试跑完,把临时数据清掉、让下一条从头开始 —— 这一步叫什么?

对。准备与收尾成对才构成一次夹具;省了收尾,这一条的残留就污染下一条,症状是单跑能过、整套跑挂。

2. 写死返回值、专门顶掉被测代码里那个网络对象的东西,叫什么?

对。替身只负责某一个外部依赖,常常是夹具准备出来之后注入被测代码的一件东西;数据是原料、断言是判据,都不是替身。

3. 同一条测试单跑能过、整套跑就挂,最可能的原因是什么?

对。几条测试共用一份没被恢复的状态,顺序一变结论就变 —— 这正是一次夹具没把前提固定住的表现。