- 测试
- Mock
- 数据脱敏
【免费下载链接】faker
Faker is a Python package that generates fake data for you.
导读
本文基于 Faker 官方文档(docs/pytest-fixtures.rst)与其 pytest 插件源码(faker/contrib/pytest/plugin.py),系统讲解 Faker 内置的fakerpytest fixture 的默认行为、Locale 与种子(seed)的配置机制,以及如何在测试套件中按需切换实例作用域。读完本文,你将掌握:开箱即用的会话级假数据实例、通过faker_session_locale/faker_locale控制语言环境、通过faker_seed保证测试可复现,以及在单个测试内对实例进行重新播种的完整实战方案。
Faker 内置的 pytest 插件:开箱即用的fakerfixture
Faker 从很早的版本起就提供了与 pytest 的一等公民集成。只要你的测试环境中安装了faker包,就可以在测试函数中直接注入名为faker的 fixture,而无需任何额外初始化:
def test_faker(faker): assert isinstance(faker.name(), str)这种零配置体验得益于 Faker 在打包时注册了 pytest 插件入口点。在 setup.py 中可以看到:
"pytest11": ["faker = faker.contrib.pytest.plugin"],pytest11是 pytest 官方约定的插件入口点,pytest 在收集阶段会自动加载 faker/contrib/pytest/plugin.py 中定义的所有 fixture。也就是说,安装 Faker 即自动注册插件,无需在conftest.py或pytest.ini中手动开启。
默认行为:会话级实例 + 种子 0 + 唯一值清理
官方文档明确指出,开箱即用时fakerfixture 具有以下三个关键默认行为:
- 会话级作用域(session-scoped):返回一个在整个测试会话中复用的
Faker实例,避免为每个测试重复实例化昂贵的对象; - 默认语言环境为
en-US:所有生成数据默认采用美式英语; - 每个测试前重新播种(seed=0):每个测试开始前实例都会用种子值
0重新播种,同时.unique记录的历史生成值会被清空。
这些行为在插件源码中均有直接对应。_session_faker是一个内部(internal)会话级 autouse fixture,它负责在会话开始时创建一次Faker实例:
# faker/contrib/pytest/plugin.py DEFAULT_SEED = 0 @pytest.fixture(scope="session", autouse=True) def _session_faker(request): """Fixture that stores the session level ``Faker`` instance. This fixture is internal and is only meant for use within the project. Third parties should instead use the ``faker`` fixture for their tests. """ if "faker_session_locale" in request.fixturenames: locale = request.getfixturevalue("faker_session_locale") else: locale = [DEFAULT_LOCALE] return Faker(locale=locale)而真正面向用户的fakerfixture 则是**函数级(function-scoped)**的,它负责在每个测试中完成"取实例 → 播种 → 清理唯一值"三步:
# faker/contrib/pytest/plugin.py @pytest.fixture() def faker(request): """Fixture that returns a seeded and suitable ``Faker`` instance.""" if "faker_locale" in request.fixturenames: locale = request.getfixturevalue("faker_locale") fake = Faker(locale=locale) else: fake = request.getfixturevalue("_session_faker") seed = DEFAULT_SEED if "faker_seed" in request.fixturenames: seed = request.getfixturevalue("faker_seed") fake.seed_instance(seed=seed) fake.unique.clear() return fake这里有一个很容易被忽略的细节:虽然对外表现是"会话级实例",但fakerfixture 本身以@pytest.fixture()声明(函数级),只是在未定义faker_locale时转发了对会话级_session_faker的引用。这正是文档中"thefakerfixture is actually a function-scoped fixture that can be configured to behave differently on demand"(docs/pytest-fixtures.rst)这句话的实现基础——它既能在默认情况下复用会话实例,又能在需要时按测试粒度切换为新实例。
默认种子值0与默认语言环境en_US分别定义在 faker/contrib/pytest/plugin.py(DEFAULT_SEED = 0)和 faker/config.py(DEFAULT_LOCALE = "en_US")中。
全局配置:通过conftest.py修改默认 Locale 与种子
如果默认的en-US与种子0不满足需求,官方文档给出的推荐做法是在顶层conftest.py中定义两个会话级(session-scoped)且 autouse的 fixture:
faker_session_locale:返回一个或多个语言环境字符串,用于指定整个测试会话使用的 Locale;faker_seed:返回一个种子值,用于指定整个测试会话的随机种子。
例如,想让所有测试使用意大利语(it_IT)且种子固定为12345,只需在顶层conftest.py中写入:
import pytest @pytest.fixture(scope='session', autouse=True) def faker_session_locale(): return ['it_IT'] @pytest.fixture(scope='session', autouse=True) def faker_seed(): return 12345结合源码可以看出两条 fixture 的读取路径完全不同:faker_session_locale由_session_faker在创建会话实例时消费一次(决定实例的语言环境),而faker_seed由fakerfixture 在每个测试执行前消费(决定每次播种的种子值)。
多语言环境支持
如果需要单实例支持多种语言,只需让faker_session_locale返回一个包含多个唯一且有效的 Locale 的列表。Faker 会为每个 Locale 创建独立的内部工厂,并根据 Locale 排序或显式指定来生成数据:
import pytest @pytest.fixture(scope='session', autouse=True) def faker_session_locale(): return ['it_IT', 'ja_JP', 'en_US']这样,同一个faker实例将同时拥有意大利语、日语和英语的数据提供者能力。
按需配置:faker_locale与局部 Locale 切换
默认的会话级实例方案覆盖了绝大多数场景,但官方文档明确提示:"there are some uncommon use cases where this approach is insufficient"(docs/pytest-fixtures.rst)。为此,插件设计了两个"覆盖开关",其生效逻辑完全依赖 pytest 原生 fixture 解析机制:
- 当某个测试的作用域内存在
faker_localefixture 时,fakerfixture 会放弃会话级实例,为该测试新建一个函数级Faker实例(见 plugin.py); - 当存在
faker_seedfixture 时,播种使用其返回值,否则回退到DEFAULT_SEED(见 plugin.py)。
官方文档特别强调,使用这一机制前需要理解 pytest 的 fixture 作用域、共享与注入规则。
场景一:仅对部分测试切换语言
如果只想让某个子模块或某些测试改用不同语言,可以在子模块的conftest.py或测试文件内部定义一个非会话级(non-session scope)的 autousefaker_locale:
import pytest @pytest.fixture(scope=any_non_session_scope, autouse=True) def faker_locale(): return ['it_IT']一旦该 fixture 生效,相关测试注入的faker就不再是会话级实例,而是新创建的函数级实例:
def test_something(faker): # The faker fixture here will return a new instance, not the session-scoped instance pass对应测试 tests/pytest/test_autouse_faker_locale.py 验证了这一点:在定义了 autousefaker_locale的前提下,即使没有定义faker_session_locale,faker != _session_faker依然成立,且faker.locales == ["it_IT"]。
场景二:显式手动注入,精细控制
如果你希望控制权更细——比如只有明确声明依赖的测试才切换到新实例——可以去掉autouse=True,改为手动注入:
import pytest @pytest.fixture() def faker_locale(): return ['it_IT'] def test_something(faker): # The faker fixture will return the session-scoped instance pass def test_something_else(faker, faker_locale): # The faker fixture will return a new instance, not the session-scoped instance pass这里test_something_else的签名中显式列出了faker_locale,pytest 会将其解析进request.fixturenames,从而触发插件源码中"faker_locale" in request.fixturenames的分支。测试 tests/pytest/test_manual_injection.py 完整覆盖了四种注入组合(不注入、仅注入 locale、仅注入 seed、同时注入两者),是理解该机制最好的运行示例:
- 不注入任何 fixture:
faker == _session_faker,语言为[DEFAULT_LOCALE],种子为DEFAULT_SEED; - 仅注入
faker_locale:新建实例,语言变为faker_locale,种子仍为DEFAULT_SEED; - 仅注入
faker_seed:仍用会话实例,种子变为faker_seed; - 同时注入两者:新建实例,且使用
faker_seed播种。
种子(Seeding)配置:独立于实例选择的播种保证
播种逻辑与默认值
fakerfixture 的播种行为与实例选择逻辑完全解耦。插件源码中,无论走哪条分支(会话实例还是新实例),最终都会执行:
fake.seed_instance(seed=seed) fake.unique.clear()这意味着:任何使用fakerfixture 的测试,无论拿到的是会话级还是函数级实例,都保证得到一个已播种的实例。seed_instance的实现位于 faker/proxy.py,它会为实例内部的每一个 Locale 工厂分别创建并播种新的random.Random对象:
def seed_instance(self, seed: SeedType | None = None) -> None: """ Creates and seeds a new `random.Random` object for each factory """ for factory in self._factories: factory.seed_instance(seed)注意这里与类方法Faker.seed()(faker/proxy.py)的区别:seed()作用于全局共享的random.Random(影响所有 Faker 实例),而seed_instance()只影响当前实例自身的随机源,互不干扰。
局部种子:作用于特定测试集合
与faker_locale同理,你可以通过定义非会话级的 autousefaker_seed让某个子模块下的所有相关测试统一使用指定种子:
import pytest @pytest.fixture(scope=any_non_session_scope, autouse=True) def faker_seed(): return 12345例如,将其声明在某个子模块的conftest.py中,则该子模块下所有相关测试的faker实例都会以12345播种。
也可以去掉autouse=True,通过手动注入实现更细粒度的控制:
import pytest @pytest.fixture(scope=any_non_session_scope) def faker_seed(): return 12345 def test_something(faker): # The faker fixture will use the session seed value pass def test_something_else(faker, faker_seed): # The faker fixture will use the seed value 12345 pass对应测试 tests/pytest/test_autouse_faker_seed.py 验证了 autousefaker_seed生效时,即使未显式注入,所有相关测试也会使用4761而非DEFAULT_SEED播种。
测试中途重新播种:seed_instance的显式调用
如果需要在同一个测试内部换用多个种子(比如分段生成互不相关的随机数据),可以直接调用实例方法faker.seed_instance(seed)。由于fakerfixture 的"每个测试前必播种"保证,测试中途的显式播种不会泄漏影响其他测试:
# Assume the active seed value is 54321 for these tests def test_something_first(faker): # The faker fixture, at first, uses seed value 54321 do_thing_a() # Explicit call to seed_instance faker.seed_instance(12345) # The faker fixture now uses seed value 12345 do_thing_b() def test_something_second(faker): # The faker fixture's seed value is still 54321, not 12345 passtest_something_second之所以仍以54321开始,是因为它在执行前重新经历了fakerfixture 的播种流程,覆盖了上一个测试中途的任何手动播种。
.unique唯一值保证:跨测试自动清理
插件在每次返回faker实例前都会调用fake.unique.clear()。这一行代码保证了唯一值代理(UniqueProxy)的记忆只存在于单个测试内部,不会因为会话级实例被多个测试共享而"污染"。
测试 tests/pytest/test_unique_clear.py 用一个非常精妙的用例验证了这一点:某个测试通过反复调用faker.boolean()消耗掉布尔值空间,随后faker.unique.boolean()触发UniquenessException;下一个测试依然能正常生成唯一布尔值,而不会因为会话级实例残留记忆而失败。该测试在testdir中动态生成三个测试函数并断言 3 个全部通过:
def test_fully_exhaust_unique_booleans(faker): _dummy = [faker.boolean() for _ in range(NUM_SAMPLES)] faker.unique.boolean() faker.unique.boolean() with pytest.raises(UniquenessException): faker.unique.boolean() _dummy = [faker.boolean() for _ in range(NUM_SAMPLES)]这印证了文档中"the.uniqueremembered generated values are cleared"(docs/pytest-fixtures.rst)的承诺,也让"每个测试只对自己的唯一性负责"成为可依赖的语义。
配置速查与决策指南
| 配置目标 | 使用的 fixture | 建议作用域 | autouse | 生效范围 |
|---|---|---|---|---|
| 全局默认 Locale | faker_session_locale | session | 是 | 整个测试会话 |
| 全局默认种子 | faker_seed | session | 是 | 整个测试会话 |
| 局部切换 Locale(自动) | faker_locale | 非 session | 是 | 所在 conftest 覆盖的测试 |
| 局部切换 Locale(手动) | faker_locale | 任意 | 否 | 显式注入该 fixture 的测试 |
| 局部种子(自动) | faker_seed | 非 session | 是 | 所在 conftest 覆盖的测试 |
| 局部种子(手动) | faker_seed | 任意 | 否 | 显式注入该 fixture 的测试 |
| 测试内重新播种 | faker.seed_instance(...) | — | — | 仅当前测试实例 |
实际选型时可以参考以下经验法则:
- 默认不写任何配置:适合大多数测试,直接享受会话级实例 + 种子 0 的确定性;
- 整个项目统一语言/种子:在顶层
conftest.py定义 session + autouse 的faker_session_locale与faker_seed; - 个别模块语言不同:在该模块的
conftest.py定义非 session 的 autousefaker_locale; - 个别测试需要精确控制:定义非 autouse 的
faker_locale/faker_seed并手动注入,或直接在测试体内调用seed_instance。
小结
Faker 的 pytest 集成是一个"默认零配置、按需深度定制"的典型设计:默认的会话级实例兼顾了性能与复用,faker_session_locale/faker_seed提供全局层面的配置入口,而faker_locale/faker_seed两个按 pytest 原生规则解析的 fixture 则打开了函数级精细控制的通道。所有行为——实例选择、播种、唯一值清理——都能在 faker/contrib/pytest/plugin.py 的四十余行代码中找到精确对应,配合 tests/pytest 目录下的四组测试(autouse locale、autouse seed、manual injection、unique clear),任何疑问都可以通过阅读源码与测试得到确证。这种"文档讲解 + 源码印证 + 测试验证"的三层结构,使得在测试中使用 Faker 既简单又完全可控。
- 测试
- Mock
- 数据脱敏
【免费下载链接】faker
Faker is a Python package that generates fake data for you.
相关推荐
Faker::Games::HeroesOfTheStorm 指南:用 Faker 生成风暴英雄假数据
Faker::Games::HeroesOfTheStorm 指南:用 Faker 生成风暴英雄假数据 导读 本文围绕 Faker 开源仓库中 Faker::G
测试开发工具Faker 生成《龙珠》风格假数据:Faker::JapaneseMedia::DragonBall 使用指南
Faker 生成《龙珠》风格假数据:Faker::JapaneseMedia::DragonBall 使用指南 本指南围绕 Faker 库(当前仓库版本 3.8
测试开发工具Faker::TvShows::SiliconValley 使用指南:用 Faker 生成《硅谷》主题假数据
Faker::TvShows::SiliconValley 使用指南:用 Faker 生成《硅谷》主题假数据 本篇指南围绕 Faker(Ruby 假数据生成库)
测试开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考