Open jamisonbryant opened 2 years ago
@jamisonbryant thank for opening the issue. A sample app would be definitely appreciated, in order to reproduce the issue.
I haven't had time to put together a sample app, but I do think I have discovered something relevant. Adding these two lines:
// vendor/vierge-noire/cakephp-fixture-factories/src/Factory/EventCollector.php:91
$conn = $table->getConnection();
echo __CLASS__ . ' table connection = ' . PHP_EOL . $conn->configName() . PHP_EOL;
prints "foo" which is one of my database connections instead of "test_foo" as I would expect.
Is it my understanding that when the Cake test suite is running, the defaultConnectionName()
of each table is supposed to be prepended by "test_" forming the complete connection name of "test_foo".
I'm not sure what an event collector does, but is there any chance it is not respecting the default cake convention for table names when running unit tests? Could that be the source of this problem?
Here is more evidence that the BaseFactory's $eventCollector is flipping back and forth between connections:
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (bottom check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = test_saas
CakephpFixtureFactories\Factory\EventCollector table connection (bottom check) = saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = saas
CakephpFixtureFactories\Factory\EventCollector table connection (top check) = saas
Top check = EventCollector::getTable() line 78, inside the if block Bottom check = EventCollector::getTable() line 99, right before the function return
Mar 2023 update: I was able to properly resolve this issue, at long last!
I was right about application code trying to access the table registry at the same time as the unit tests, and using different connections to do so. E.g. my fixture factories would create and persist entities using the test
connection, and my app would do the same except using the app
connection. For my project, these are two different databases.
The solution is to alias the connections in the test bootstrapper:
// file: tests/bootstrap.php
$testDatasource = 'foo';
try {
ConnectionManager::get($testDatasource);
ConnectionManager::alias($testDatasource, 'default');
ConnectionManager::alias($testDatasource, 'test');
ConnectionManager::alias($testDatasource, 'other');
//(new SchemaLoader())->loadSqlFiles(TESTS . 'schema.sql', $testConnection);
(new Migrator())->run(['connection' => $testDatasource]);
} catch (MissingDatasourceConfigException $e) {
trigger_error("Cannot run the test suite: missing connection '{$testDatasource}'. Check main config file.");
}
Now, even when the application tries to use the "wrong" database connection, it will go to the correct database.
I'm not sure there's a change to be made to Fixture Factories unless it's a docs clarification, do you agree @pabloelcolombiano?
This was the bug at the bottom of a well that I spent many, many days trying to diagnose.
Description of the problem
It appears that if fixture factories touch a table and then downstream application code also does, entity creation does not work for that table in the application code.
How to reproduce
AccessTokensTable
and returns them (they are not persisted).BadTest
.InnocentTest
) which is an Integration test. Several tests within itPOST
to a controller action in my application code.AccessTokensTable
). This entity should be persisted, by the app.I was able to confirm that the problem occurs as a result of the call to
AccessTokensFactory::make()
, as refactoring my test data provider to manually construct the entities instead of calling the fixture factory results in all tests in theInnocentTest
test class passing once again.Expected behavior
Whatever magic the fixture factories do to the tables in order to create entities, that magic does not interfere with application code being able to interface with the tables and make entities downstream.
Let me know if all this is clear? I can try to put together an open-source sample app if needed.