Commit 12ff8630 by Qiang Xue

refactored fixture implementation.

parent 106e9124
...@@ -118,7 +118,7 @@ use app\tests\fixtures\UserProfileFixture; ...@@ -118,7 +118,7 @@ use app\tests\fixtures\UserProfileFixture;
class UserProfileTest extends TestCase class UserProfileTest extends TestCase
{ {
public function fixtures() protected function fixtures()
{ {
return [ return [
'profiles' => UserProfileFixture::className(), 'profiles' => UserProfileFixture::className(),
......
...@@ -49,45 +49,6 @@ class TestCase extends Test ...@@ -49,45 +49,6 @@ class TestCase extends Test
} }
/** /**
* Returns the value of an object property.
*
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `$value = $object->property;`.
* @param string $name the property name
* @return mixed the property value
* @throws UnknownPropertyException if the property is not defined
*/
public function __get($name)
{
$fixture = $this->getFixture($name);
if ($fixture !== null) {
return $fixture;
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
}
/**
* Calls the named method which is not a class method.
*
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when an unknown method is being invoked.
* @param string $name the method name
* @param array $params method parameters
* @throws UnknownMethodException when calling unknown method
* @return mixed the method return value
*/
public function __call($name, $params)
{
$fixture = $this->getFixture($name);
if ($fixture instanceof ActiveFixture) {
return $fixture->getModel(reset($params));
} else {
throw new UnknownMethodException('Unknown method: ' . get_class($this) . "::$name()");
}
}
/**
* Mocks up the application instance. * Mocks up the application instance.
* @param array $config the configuration that should be used to generate the application instance. * @param array $config the configuration that should be used to generate the application instance.
* If null, [[appConfig]] will be used. * If null, [[appConfig]] will be used.
......
...@@ -9,16 +9,75 @@ namespace yii\test; ...@@ -9,16 +9,75 @@ namespace yii\test;
use Yii; use Yii;
use yii\base\InvalidConfigException; 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. * FixtureTrait provides functionalities for loading, unloading and accessing fixtures for a test case.
* *
* By using FixtureTrait, a test class will be able to specify which fixtures to load by overriding
* the [[fixtures()]] method. It can then load and unload the fixtures using [[loadFixtures()]] and [[unloadFixtures()]].
* Once a fixture is loaded, it can be accessed like an object property, thanks to the PHP `__get()` magic method.
* Also, if the fixture is an instance of [[ActiveFixture]], you will be able to access AR models
* through the syntax `$this->fixtureName('model name')`.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
trait FixtureTrait trait FixtureTrait
{ {
/** /**
* @var array the list of fixture objects available for the current test.
* The array keys are the corresponding fixture class names.
* The fixtures are listed in their dependency order. That is, fixture A is listed before B
* if B depends on A.
*/
private $_fixtures;
/**
* @var array the fixture class names indexed by the corresponding fixture names (aliases).
*/
private $_fixtureAliases;
/**
* Returns the value of an object property.
*
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `$value = $object->property;`.
* @param string $name the property name
* @return mixed the property value
* @throws UnknownPropertyException if the property is not defined
*/
public function __get($name)
{
$fixture = $this->getFixture($name);
if ($fixture !== null) {
return $fixture;
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
}
/**
* Calls the named method which is not a class method.
*
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when an unknown method is being invoked.
* @param string $name the method name
* @param array $params method parameters
* @throws UnknownMethodException when calling unknown method
* @return mixed the method return value
*/
public function __call($name, $params)
{
$fixture = $this->getFixture($name);
if ($fixture instanceof ActiveFixture) {
return $fixture->getModel(reset($params));
} else {
throw new UnknownMethodException('Unknown method: ' . get_class($this) . "::$name()");
}
}
/**
* Declares the fixtures that are needed by the current test case. * Declares the fixtures that are needed by the current test case.
* The return value of this method must be an array of fixture configurations. For example, * The return value of this method must be an array of fixture configurations. For example,
* *
...@@ -38,31 +97,19 @@ trait FixtureTrait ...@@ -38,31 +97,19 @@ trait FixtureTrait
* *
* @return array the fixtures needed by the current test case * @return array the fixtures needed by the current test case
*/ */
public function fixtures() protected function fixtures()
{ {
return []; return [];
} }
/** /**
* @var array the list of fixture objects available for the current test.
* The array keys are the corresponding fixture class names.
* The fixtures are listed in their dependency order. That is, fixture A is listed before B
* if B depends on A.
*/
private $_fixtures;
/**
* @var array the fixture class names indexed by the corresponding fixture names (aliases).
*/
private $_fixtureAliases;
/**
* Loads the fixtures. * Loads the fixtures.
* This method will load the fixtures specified by `$fixtures` or [[fixtures()]]. * This method will load the fixtures specified by `$fixtures` or [[fixtures()]].
* @param array $fixtures the fixtures to loaded. If not set, [[fixtures()]] will be loaded instead. * @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 * @throws InvalidConfigException if fixtures are not properly configured or if a circular dependency among
* the fixtures is detected. * the fixtures is detected.
*/ */
public function loadFixtures($fixtures = null) protected function loadFixtures($fixtures = null)
{ {
if ($fixtures === null) { if ($fixtures === null) {
$fixtures = $this->fixtures(); $fixtures = $this->fixtures();
...@@ -120,7 +167,7 @@ trait FixtureTrait ...@@ -120,7 +167,7 @@ trait FixtureTrait
/** /**
* Unloads all existing fixtures. * Unloads all existing fixtures.
*/ */
public function unloadFixtures() protected function unloadFixtures()
{ {
/** @var Fixture $fixture */ /** @var Fixture $fixture */
foreach (array_reverse($this->_fixtures) as $fixture) { foreach (array_reverse($this->_fixtures) as $fixture) {
...@@ -131,7 +178,7 @@ trait FixtureTrait ...@@ -131,7 +178,7 @@ trait FixtureTrait
/** /**
* @return array the loaded fixtures for the current test case * @return array the loaded fixtures for the current test case
*/ */
public function getFixtures() protected function getFixtures()
{ {
return $this->_fixtures; return $this->_fixtures;
} }
...@@ -141,7 +188,7 @@ trait FixtureTrait ...@@ -141,7 +188,7 @@ trait FixtureTrait
* @param string $name the fixture alias or class name * @param string $name the fixture alias or class name
* @return Fixture the fixture object, or null if the named fixture does not exist. * @return Fixture the fixture object, or null if the named fixture does not exist.
*/ */
public function getFixture($name) protected function getFixture($name)
{ {
$class = isset($this->_fixtureAliases[$name]) ? $this->_fixtureAliases[$name] : $name; $class = isset($this->_fixtureAliases[$name]) ? $this->_fixtureAliases[$name] : $name;
return isset($this->_fixtures[$class]) ? $this->_fixtures[$class] : null; return isset($this->_fixtures[$class]) ? $this->_fixtures[$class] : null;
......
...@@ -21,7 +21,17 @@ class MyDbTestCase ...@@ -21,7 +21,17 @@ class MyDbTestCase
{ {
use FixtureTrait; use FixtureTrait;
public function fixtures() public function setUp()
{
$this->loadFixtures();
}
public function tearDown()
{
$this->unloadFixtures();
}
protected function fixtures()
{ {
return [ return [
'customers' => CustomerFixture::className(), 'customers' => CustomerFixture::className(),
...@@ -51,8 +61,8 @@ class ActiveFixtureTest extends DatabaseTestCase ...@@ -51,8 +61,8 @@ class ActiveFixtureTest extends DatabaseTestCase
public function testGetRows() public function testGetRows()
{ {
$test = new MyDbTestCase(); $test = new MyDbTestCase();
$test->loadFixtures(); $test->setUp();
$fixture = $test->getFixture('customers'); $fixture = $test->customers;
$this->assertEquals(CustomerFixture::className(), get_class($fixture)); $this->assertEquals(CustomerFixture::className(), get_class($fixture));
$this->assertEquals(2, count($fixture)); $this->assertEquals(2, count($fixture));
$this->assertEquals(1, $fixture['customer1']['id']); $this->assertEquals(1, $fixture['customer1']['id']);
...@@ -64,8 +74,8 @@ class ActiveFixtureTest extends DatabaseTestCase ...@@ -64,8 +74,8 @@ class ActiveFixtureTest extends DatabaseTestCase
public function testGetModel() public function testGetModel()
{ {
$test = new MyDbTestCase(); $test = new MyDbTestCase();
$test->loadFixtures(); $test->setUp();
$fixture = $test->getFixture('customers'); $fixture = $test->customers;
$this->assertEquals(Customer::className(), get_class($fixture->getModel('customer1'))); $this->assertEquals(Customer::className(), get_class($fixture->getModel('customer1')));
$this->assertEquals(1, $fixture->getModel('customer1')->id); $this->assertEquals(1, $fixture->getModel('customer1')->id);
$this->assertEquals('customer1@example.com', $fixture->getModel('customer1')->email); $this->assertEquals('customer1@example.com', $fixture->getModel('customer1')->email);
......
...@@ -63,7 +63,22 @@ class MyTestCase ...@@ -63,7 +63,22 @@ class MyTestCase
public static $load; public static $load;
public static $unload; public static $unload;
public function fixtures() public function setUp()
{
$this->loadFixtures();
}
public function tearDown()
{
$this->unloadFixtures();
}
public function fetchFixture($name)
{
return $this->getFixture($name);
}
protected function fixtures()
{ {
switch ($this->scenario) { switch ($this->scenario) {
case 0: return []; case 0: return [];
...@@ -105,9 +120,9 @@ class FixtureTest extends TestCase ...@@ -105,9 +120,9 @@ class FixtureTest extends TestCase
foreach ($this->getDependencyTests() as $scenario => $result) { foreach ($this->getDependencyTests() as $scenario => $result) {
$test = new MyTestCase(); $test = new MyTestCase();
$test->scenario = $scenario; $test->scenario = $scenario;
$test->loadFixtures(); $test->setUp();
foreach ($result as $name => $loaded) { foreach ($result as $name => $loaded) {
$this->assertEquals($loaded, $test->getFixture($name) !== null, "Verifying scenario $scenario fixture $name"); $this->assertEquals($loaded, $test->fetchFixture($name) !== null, "Verifying scenario $scenario fixture $name");
} }
} }
} }
...@@ -119,9 +134,9 @@ class FixtureTest extends TestCase ...@@ -119,9 +134,9 @@ class FixtureTest extends TestCase
$test->scenario = $scenario; $test->scenario = $scenario;
MyTestCase::$load = ''; MyTestCase::$load = '';
MyTestCase::$unload = ''; MyTestCase::$unload = '';
$test->loadFixtures(); $test->setUp();
$this->assertEquals($result[0], MyTestCase::$load, "Verifying scenario $scenario load sequence"); $this->assertEquals($result[0], MyTestCase::$load, "Verifying scenario $scenario load sequence");
$test->unloadFixtures(); $test->tearDown();
$this->assertEquals($result[1], MyTestCase::$unload, "Verifying scenario $scenario unload sequence"); $this->assertEquals($result[1], MyTestCase::$unload, "Verifying scenario $scenario unload sequence");
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment