Symfony测试环境需显式启用test.service_container、配置内存SQLite或DAMA事务隔离、使用resolve:前缀解析%env(DATABASE_URL)%,否则将出现ServiceNotFoundException或连接失败。

测试环境不是靠“设个 APP_ENV=test”就自动生效的——它必须显式启用容器扩展、加载对应配置、并确保 Doctrine 和服务能被正确访问。否则你会遇到 ServiceNotFoundException、EntityManager 为 null、或 fixture 数据不回滚等问题。
test.service_container 必须手动启用
Symfony 默认禁用测试专用服务容器,导致你在 KernelTestCase 里无法获取私有服务(比如 doctrine.orm.default_entity_manager)。不启用它,$this->getContainer()->get() 会直接抛异常。
- 在
config/packages/test/framework.yaml中添加:framework: test: true session: storage_id: session.storage.mock_file - 确保
config/services_test.yaml存在且被加载(Symfony 5.4+ 默认由 Kernel 自动 import) - 若使用自定义测试基类,别漏掉
self::bootKernel(['environment' => 'test'])—— 单纯设APP_ENV=test环境变量不够
数据库连接必须走内存 SQLite 或事务隔离
用 sqlite:///:memory: 是最快最干净的方式,但前提是 Doctrine 配置里没硬编码驱动选项;若你改用 MySQL/PostgreSQL 测试库,就必须配 DAMA\DoctrineTestBundle 来保证事务级隔离,否则测试间数据污染不可避免。
- 在
.env.test中设:DATABASE_URL=sqlite:///:memory: - 在
config/packages/test/doctrine.yaml中确认覆盖了连接 URL:doctrine: dbal: url: '%env(resolve:DATABASE_URL)%' - 若不用内存库,装 DAMA:
composer require --dev dama/doctrine-test-bundle,并在config/bundles.php中注册它(仅 test 环境)
fixtures 加载逻辑要匹配测试类型
用 DoctrineFixturesBundle 的 load() 方法在每个测试前重刷数据?错——这太慢,且和事务模式冲突。真正该做的是:单元测试绕过 fixtures,集成测试用 Foundry 按需生成,功能测试靠 DAMA 的事务自动回滚。
- 删掉
tests/bootstrap.php里手动调用FixtureLoader的代码 - 改用 Foundry(推荐):
UserFactory::createOne(['email' => 'test@example.com']),它默认走当前 EntityManager,且不触发 flush 直到你明确调用 - 如果坚持用 Fixtures,在
setUp()里别调$loader->loadFromDirectory(),而是用DAMA\DoctrineTestBundle\Doctrine\DBAL\StaticDriver::setKeepStaticConnections(true)配合事务
最常被忽略的一点:.env.test 文件里的变量不会自动注入到参数中,%env(DATABASE_URL)% 在 test 环境下必须带 resolve: 前缀,否则就是字面字符串——这个细节导致大量人卡在 “Connection refused” 错误上,其实只是 URL 根本没解析。


















