Symfony 4测试时如何切换使用的数据库连接?
test_gui in Symfony Tests Great question! Let's break down a few solid ways to make your userRegistrationDatabase function use the test_gui entity manager during tests, depending on how much you want to adjust your existing code.
Option 1: Environment Configuration Swap (Simplest Approach)
Symfony lets you override configuration per environment, so you can make the gui entity manager point to your test SQLite database when running tests. No changes to your business code needed!
- Create or update the test environment Doctrine config at
config/packages/test/doctrine.yaml:
doctrine: dbal: connections: test_gui: url: '%env(resolve:DATABASE_TEST_GUI_URL)%' driver: pdo_sqlite # Add any other test-specific DB settings here orm: entity_managers: gui: # Keep the original manager name, but map it to the test connection connection: test_gui mappings: App: is_bundle: false dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App
- Update your
.env.testfile to define the test database URL:
DATABASE_TEST_GUI_URL="sqlite:///%kernel.project_dir%/var/data/test_gui.db"
Now when you run tests, $this->getDoctrine()->getManager("gui") will automatically use the test_gui connection—your business code stays exactly the same.
Option 2: Inject the Entity Manager (Cleanest, Most Maintainable)
Instead of hardcoding getManager("gui") in your service, inject the entity manager directly. This makes swapping it for tests trivial and aligns with Symfony's best practices.
Step 1: Refactor your service to use dependency injection
use Doctrine\ORM\EntityManagerInterface; class UserManagement { private EntityManagerInterface $guiEntityManager; // Inject the gui entity manager via constructor public function __construct(EntityManagerInterface $guiEntityManager) { $this->guiEntityManager = $guiEntityManager; } public function userRegistrationDatabase(String $email, String $keyRockId): object { $user = new User(); $user->setUserName($email); $user->setEmail($email); $user->setEnabled(true); $userRole = ['ROLE_USER','ROLE_ADMIN']; $user->addRole(implode(",",$userRole)); $user->setKeyrockId($keyRockId); // Use the injected manager instead of fetching it $this->guiEntityManager->persist($user); $this->guiEntityManager->flush(); return $user; } }
Step 2: Configure the service in config/services.yaml
Bind the gui entity manager to your service:
services: App\Service\UserManagement: arguments: $guiEntityManager: '@doctrine.orm.gui_entity_manager'
Step 3: Override for tests in config/packages/test/services.yaml
Swap the injected manager for test_gui:
services: App\Service\UserManagement: arguments: $guiEntityManager: '@doctrine.orm.test_gui_entity_manager'
Now your test will automatically use the test_gui manager without any extra code in the test function.
Option 3: Manual Swap with Reflection (Quick Fix, Not Ideal)
If you can't modify the service or config right now, you can use reflection to force the service to use the test manager. This is a temporary workaround—prefer the other options long-term.
public function testUserRegistrationDatabase() { $userManager = self::$kernel->getContainer()->get('test.'. UserManagement::class); $testEntityManager = self::$kernel->getContainer()->get('doctrine')->getManager('test_gui'); // Use reflection to access the private $entityManager property in UserManagement $reflection = new \ReflectionClass($userManager); $entityManagerProp = $reflection->getProperty('entityManager'); $entityManagerProp->setAccessible(true); $entityManagerProp->setValue($userManager, $testEntityManager); $mail = 'notexistinguser@mail.com'; $keyRockId = '45091fd63a1'; $user = $userManager->userRegistrationDatabase($mail,$keyRockId); }
Just note: This relies on the internal property name ($entityManager) staying the same, so it's fragile if you refactor later.
内容的提问来源于stack exchange,提问作者Stefano Maglione

