From 11bc899bc122e4ada5182f1066e4527ea912233e Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 3 Feb 2014 21:16:57 -0500 Subject: [PATCH] Refactored fixtures and fixed test break. --- extensions/codeception/TestCase.php | 5 +- .../console/controllers/FixtureController.php | 31 +++- framework/test/Fixture.php | 14 ++ framework/test/FixtureTrait.php | 153 +++++++++++------- framework/test/InitDbFixture.php | 20 +++ .../unit/framework/test/ActiveFixtureTest.php | 2 +- 6 files changed, 159 insertions(+), 66 deletions(-) diff --git a/extensions/codeception/TestCase.php b/extensions/codeception/TestCase.php index d1cfb7fa84..3ba95265f8 100644 --- a/extensions/codeception/TestCase.php +++ b/extensions/codeception/TestCase.php @@ -5,6 +5,9 @@ namespace yii\codeception; use Yii; use yii\base\InvalidConfigException; use Codeception\TestCase\Test; +use yii\base\UnknownMethodException; +use yii\base\UnknownPropertyException; +use yii\test\ActiveFixture; use yii\test\FixtureTrait; /** @@ -71,6 +74,7 @@ class TestCase extends Test { parent::setUp(); $this->mockApplication(); + $this->unloadFixtures(); $this->loadFixtures(); } @@ -79,7 +83,6 @@ class TestCase extends Test */ protected function tearDown() { - $this->unloadFixtures(); $this->destroyApplication(); parent::tearDown(); } diff --git a/framework/console/controllers/FixtureController.php b/framework/console/controllers/FixtureController.php index 186e1da197..c16e4a7493 100644 --- a/framework/console/controllers/FixtureController.php +++ b/framework/console/controllers/FixtureController.php @@ -119,11 +119,25 @@ class FixtureController extends Controller throw new Exception('No fixtures were found in namespace: "' . $this->namespace . '"' . ''); } + $fixtures = $this->createFixtures($fixtures); + $transaction = Yii::$app->db->beginTransaction(); try { $this->getDbConnection()->createCommand()->checkIntegrity(false)->execute(); - $this->loadFixtures($fixtures); + + /** @var \yii\test\Fixture $fixture */ + foreach ($fixtures as $fixture) { + $fixture->beforeLoad(); + } + foreach ($fixtures as $fixture) { + $fixture->load(); + } + foreach (array_reverse($fixtures) as $fixture) { + $fixture->afterLoad(); + $this->stdout(" Fixture \"{$fixture::className()}\" was successfully loaded. \n", Console::FG_GREEN); + } + $this->getDbConnection()->createCommand()->checkIntegrity(true)->execute(); $transaction->commit(); } catch (\Exception $e) { @@ -169,15 +183,24 @@ class FixtureController extends Controller throw new Exception('No fixtures were found in namespace: ' . $this->namespace . '".'); } + $fixtures = $this->createFixtures($fixtures); + $transaction = Yii::$app->db->beginTransaction(); try { $this->getDbConnection()->createCommand()->checkIntegrity(false)->execute(); - foreach ($fixtures as $fixtureConfig) { - $fixture = Yii::createObject($fixtureConfig); + /** @var \yii\test\Fixture $fixture */ + foreach ($fixtures as $fixture) { + $fixture->beforeUnload(); + } + $fixtures = array_reverse($fixtures); + foreach ($fixtures as $fixture) { $fixture->unload(); - $this->stdout("\tFixture \"{$fixture::className()}\" was successfully unloaded. \n", Console::FG_GREEN); + } + foreach ($fixtures as $fixture) { + $fixture->afterUnload(); + $this->stdout(" Fixture \"{$fixture::className()}\" was successfully unloaded. \n", Console::FG_GREEN); } $this->getDbConnection()->createCommand()->checkIntegrity(true)->execute(); diff --git a/framework/test/Fixture.php b/framework/test/Fixture.php index bf2905b33e..5a38ae513b 100644 --- a/framework/test/Fixture.php +++ b/framework/test/Fixture.php @@ -67,5 +67,19 @@ class Fixture extends Component public function unload() { } + + /** + * This method is called BEFORE any fixture data is unloaded for the current test. + */ + public function beforeUnload() + { + } + + /** + * This method is called AFTER all fixture data have been unloaded for the current test. + */ + public function afterUnload() + { + } } diff --git a/framework/test/FixtureTrait.php b/framework/test/FixtureTrait.php index b73312864c..f82c56d86f 100644 --- a/framework/test/FixtureTrait.php +++ b/framework/test/FixtureTrait.php @@ -9,8 +9,6 @@ namespace yii\test; use Yii; use yii\base\InvalidConfigException; -use yii\base\UnknownMethodException; -use yii\base\UnknownPropertyException; /** * FixtureTrait provides functionalities for loading, unloading and accessing fixtures for a test case. @@ -33,10 +31,6 @@ trait FixtureTrait * if B depends on A. */ private $_fixtures; - /** - * @var array the fixture class names indexed by the corresponding fixture names (aliases). - */ - private $_fixtureAliases; /** * Declares the fixtures that are needed by the current test case. @@ -79,94 +73,133 @@ trait FixtureTrait } /** - * Loads the fixtures. - * This method will load the fixtures specified by `$fixtures` or [[globalFixtures()]] and [[fixtures()]]. - * @param array $fixtures the fixtures to loaded. If not set, [[fixtures()]] will be loaded instead. - * @throws InvalidConfigException if fixtures are not properly configured or if a circular dependency among - * the fixtures is detected. + * Loads the specified fixtures. + * This method will call [[Fixture::load()]] for every fixture object. + * @param Fixture[] $fixtures the fixtures to be loaded. If this parameter is not specified, + * the return value of [[getFixtures()]] will be used. */ - protected function loadFixtures($fixtures = null) + public function loadFixtures($fixtures = null) { if ($fixtures === null) { - $fixtures = array_merge($this->globalFixtures(), $this->fixtures()); + $fixtures = $this->getFixtures(); } - // normalize fixture configurations - $config = []; // configuration provided in test case - $this->_fixtureAliases = []; - foreach ($fixtures as $name => $fixture) { - if (!is_array($fixture)) { - $fixtures[$name] = $fixture = ['class' => $fixture]; - } elseif (!isset($fixture['class'])) { - throw new InvalidConfigException("You must specify 'class' for the fixture '$name'."); - } - $config[$fixture['class']] = $fixture; - $this->_fixtureAliases[$name] = $fixture['class']; - } - - // create fixture instances - $this->_fixtures = []; - $stack = array_reverse($fixtures); - while (($fixture = array_pop($stack)) !== null) { - if ($fixture instanceof Fixture) { - $class = get_class($fixture); - unset($this->_fixtures[$class]); // unset so that the fixture is added to the last in the next line - $this->_fixtures[$class] = $fixture; - } else { - $class = $fixture['class']; - if (!isset($this->_fixtures[$class])) { - $this->_fixtures[$class] = false; - $stack[] = $fixture = Yii::createObject($fixture); - foreach ($fixture->depends as $dep) { - // need to use the configuration provided in test case - $stack[] = isset($config[$dep]) ? $config[$dep] : ['class' => $dep]; - } - } elseif ($this->_fixtures[$class] === false) { - throw new InvalidConfigException("A circular dependency is detected for fixture '$class'."); - } - } - } - - // load fixtures /** @var Fixture $fixture */ - foreach ($this->_fixtures as $fixture) { + foreach ($fixtures as $fixture) { $fixture->beforeLoad(); } - foreach ($this->_fixtures as $fixture) { + foreach ($fixtures as $fixture) { $fixture->load(); } - foreach ($this->_fixtures as $fixture) { + foreach (array_reverse($fixtures) as $fixture) { $fixture->afterLoad(); } } /** - * Unloads all existing fixtures. + * Unloads the specified fixtures. + * This method will call [[Fixture::unload()]] for every fixture object. + * @param Fixture[] $fixtures the fixtures to be loaded. If this parameter is not specified, + * the return value of [[getFixtures()]] will be used. */ - protected function unloadFixtures() + public function unloadFixtures($fixtures = null) { + if ($fixtures === null) { + $fixtures = $this->getFixtures(); + } + /** @var Fixture $fixture */ - foreach (array_reverse($this->_fixtures) as $fixture) { + foreach ($fixtures as $fixture) { + $fixture->beforeUnload(); + } + $fixtures = array_reverse($fixtures); + foreach ($fixtures as $fixture) { $fixture->unload(); } + foreach ($fixtures as $fixture) { + $fixture->afterUnload(); + } } /** - * @return array the loaded fixtures for the current test case + * Returns the fixture objects as specified in [[globalFixtures()]] and [[fixtures()]]. + * @return Fixture[] the loaded fixtures for the current test case */ public function getFixtures() { + if ($this->_fixtures === null) { + $this->_fixtures = $this->createFixtures(array_merge($this->globalFixtures(), $this->fixtures())); + } return $this->_fixtures; } /** * Returns the named fixture. - * @param string $name the fixture alias or class name + * @param string $name the fixture name. This can be either the fixture alias name, or the class name if the alias is not used. * @return Fixture the fixture object, or null if the named fixture does not exist. */ public function getFixture($name) { - $class = isset($this->_fixtureAliases[$name]) ? $this->_fixtureAliases[$name] : $name; - return isset($this->_fixtures[$class]) ? $this->_fixtures[$class] : null; + if ($this->_fixtures === null) { + $this->_fixtures = $this->createFixtures(array_merge($this->globalFixtures(), $this->fixtures())); + } + $name = ltrim($name, '\\'); + return isset($this->_fixtures[$name]) ? $this->_fixtures[$name] : null; + } + + /** + * Creates the specified fixture instances. + * All dependent fixtures will also be created. + * @param array $fixtures the fixtures to be created. You may provide fixture names or fixture configurations. + * If this parameter is not provided, the fixtures specified in [[globalFixtures()]] and [[fixtures()]] will be created. + * @return Fixture[] the created fixture instances + * @throws InvalidConfigException if fixtures are not properly configured or if a circular dependency among + * the fixtures is detected. + */ + protected function createFixtures(array $fixtures) + { + // normalize fixture configurations + $config = []; // configuration provided in test case + $aliases = []; // class name => alias or class name + foreach ($fixtures as $name => $fixture) { + if (!is_array($fixture)) { + $class = ltrim($fixture, '\\'); + $fixtures[$name] = ['class' => $class]; + $aliases[$class] = is_integer($name) ? $class : $name; + } elseif (isset($fixture['class'])) { + $class = ltrim($fixture['class'], '\\'); + $config[$class] = $fixture; + $aliases[$class] = $name; + } else { + throw new InvalidConfigException("You must specify 'class' for the fixture '$name'."); + } + } + + // create fixture instances + $instances = []; + $stack = array_reverse($fixtures); + while (($fixture = array_pop($stack)) !== null) { + if ($fixture instanceof Fixture) { + $class = get_class($fixture); + $name = isset($aliases[$class]) ? $aliases[$class] : $class; + unset($instances[$name]); // unset so that the fixture is added to the last in the next line + $instances[$name] = $fixture; + } else { + $class = ltrim($fixture['class'], '\\'); + $name = isset($aliases[$class]) ? $aliases[$class] : $class; + if (!isset($instances[$name])) { + $instances[$name] = false; + $stack[] = $fixture = Yii::createObject($fixture); + foreach ($fixture->depends as $dep) { + // need to use the configuration provided in test case + $stack[] = isset($config[$dep]) ? $config[$dep] : ['class' => $dep]; + } + } elseif ($instances[$name] === false) { + throw new InvalidConfigException("A circular dependency is detected for fixture '$class'."); + } + } + } + + return $instances; } } diff --git a/framework/test/InitDbFixture.php b/framework/test/InitDbFixture.php index 9e46427473..9c5f63352b 100644 --- a/framework/test/InitDbFixture.php +++ b/framework/test/InitDbFixture.php @@ -72,6 +72,26 @@ class InitDbFixture extends DbFixture } } + /** + * @inheritdoc + */ + public function beforeUnload() + { + foreach ($this->schemas as $schema) { + $this->checkIntegrity(false, $schema); + } + } + + /** + * @inheritdoc + */ + public function afterUnload() + { + foreach ($this->schemas as $schema) { + $this->checkIntegrity(true, $schema); + } + } + /** * Toggles the DB integrity check. * @param boolean $check whether to turn on or off the integrity check. diff --git a/tests/unit/framework/test/ActiveFixtureTest.php b/tests/unit/framework/test/ActiveFixtureTest.php index 4ff7cb1257..a5ba139b2d 100644 --- a/tests/unit/framework/test/ActiveFixtureTest.php +++ b/tests/unit/framework/test/ActiveFixtureTest.php @@ -25,12 +25,12 @@ class MyDbTestCase public function setUp() { + $this->unloadFixtures(); $this->loadFixtures(); } public function tearDown() { - $this->unloadFixtures(); } public function fixtures()