40 changed files with 694 additions and 133 deletions
			
			
		| @ -0,0 +1,219 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\test; | ||||
| 
 | ||||
| use Yii; | ||||
| use yii\base\Component; | ||||
| use yii\base\InvalidConfigException; | ||||
| use yii\db\ActiveRecord; | ||||
| use yii\db\Connection; | ||||
| 
 | ||||
| /** | ||||
|  * DbFixtureManager manages database fixtures during tests. | ||||
|  * | ||||
|  * A fixture represents a list of rows for a specific table. For a test method, | ||||
|  * using a fixture means that at the beginning of the method, the table has and only | ||||
|  * has the rows that are given in the fixture. Therefore, the table's state is | ||||
|  * predictable. | ||||
|  * | ||||
|  * A fixture is represented as a PHP script whose name (without suffix) is the | ||||
|  * same as the table name (if schema name is needed, it should be prefixed to | ||||
|  * the table name). The PHP script returns an array representing a list of table | ||||
|  * rows. Each row is an associative array of column values indexed by column names. | ||||
|  * | ||||
|  * Fixtures must be stored under the [[basePath]] directory. The directory | ||||
|  * may contain a file named `init.php` which will be executed before any fixture is loaded. | ||||
|  * | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class DbFixtureManager extends Component | ||||
| { | ||||
| 	/** | ||||
| 	 * @var string the init script file that should be executed before running each test. | ||||
| 	 * This should be a path relative to [[basePath]]. | ||||
| 	 */ | ||||
| 	public $initScript = 'init.php'; | ||||
| 	/** | ||||
| 	 * @var string the base path containing all fixtures. This can be either a directory path or path alias. | ||||
| 	 */ | ||||
| 	public $basePath = '@app/tests/fixtures'; | ||||
| 	/** | ||||
| 	 * @var Connection|string the DB connection object or the application component ID of the DB connection. | ||||
| 	 * After the DbFixtureManager object is created, if you want to change this property, you should only assign it | ||||
| 	 * with a DB connection object. | ||||
| 	 */ | ||||
| 	public $db = 'db'; | ||||
| 	/** | ||||
| 	 * @var array list of database schemas that the test tables may reside in. Defaults to | ||||
| 	 * array(''), meaning using the default schema (an empty string refers to the | ||||
| 	 * default schema). This property is mainly used when turning on and off integrity checks | ||||
| 	 * so that fixture data can be populated into the database without causing problem. | ||||
| 	 */ | ||||
| 	public $schemas = ['']; | ||||
| 
 | ||||
| 	private $_rows; // fixture name, row alias => row | ||||
| 	private $_models; // fixture name, row alias => record (or class name) | ||||
| 	private $_modelClasses; | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Loads the specified fixtures. | ||||
| 	 * | ||||
| 	 * This method does the following things to load the fixtures: | ||||
| 	 * | ||||
| 	 * - Run [[initScript]] if any. | ||||
| 	 * - Clean up data and models loaded in memory previously. | ||||
| 	 * - Load each specified fixture by calling [[loadFixture()]]. | ||||
| 	 * | ||||
| 	 * @param array $fixtures a list of fixtures (fixture name => table name or AR class name) to be loaded. | ||||
| 	 * Each array element can be either a table name (with schema prefix if needed), or a fully-qualified | ||||
| 	 * ActiveRecord class name (e.g. `app\models\Post`). An element can be associated with a key | ||||
| 	 * which will be treated as the fixture name. | ||||
| 	 * @return array the loaded fixture data (fixture name => table rows) | ||||
| 	 * @throws InvalidConfigException if a model class specifying a fixture is not an ActiveRecord class. | ||||
| 	 */ | ||||
| 	public function load(array $fixtures = []) | ||||
| 	{ | ||||
| 		$this->basePath = Yii::getAlias($this->basePath); | ||||
| 
 | ||||
| 		if (is_string($this->db)) { | ||||
| 			$this->db = Yii::$app->getComponent($this->db); | ||||
| 		} | ||||
| 		if (!$this->db instanceof Connection) { | ||||
| 			throw new InvalidConfigException("The 'db' property must be either a DB connection instance or the application component ID of a DB connection."); | ||||
| 		} | ||||
| 
 | ||||
| 		foreach ($fixtures as $name => $fixture) { | ||||
| 			if (strpos($fixture, '\\') !== false) { | ||||
| 				$model = new $fixture; | ||||
| 				if ($model instanceof ActiveRecord) { | ||||
| 					$this->_modelClasses[$name] = $fixture; | ||||
| 					$fixtures[$name] = $model->getTableSchema()->name; | ||||
| 				} else { | ||||
| 					throw new InvalidConfigException("Fixture '$fixture' must be an ActiveRecord class."); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$this->_modelClasses = $this->_rows = $this->_models = []; | ||||
| 
 | ||||
| 		$this->checkIntegrity(false); | ||||
| 
 | ||||
| 		if (!empty($this->initScript)) { | ||||
| 			$initFile = $this->basePath . '/' . $this->initScript; | ||||
| 			if (is_file($initFile)) { | ||||
| 				require($initFile); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		foreach ($fixtures as $name => $tableName) { | ||||
| 			$rows = $this->loadFixture($tableName); | ||||
| 			if (is_array($rows)) { | ||||
| 				$this->_rows[$name] = $rows; | ||||
| 			} | ||||
| 		} | ||||
| 		$this->checkIntegrity(true); | ||||
| 		return $this->_rows; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Loads the fixture for the specified table. | ||||
| 	 * | ||||
| 	 * This method does the following tasks to load the fixture for a table: | ||||
| 	 * | ||||
| 	 * - Remove existing rows in the table. | ||||
| 	 * - If there is any auto-incremental column, the corresponding sequence will be reset to 0. | ||||
| 	 * - If a fixture file is found, it will be executed, and its return value will be treated | ||||
| 	 *   as rows which will then be inserted into the table. | ||||
| 	 * | ||||
| 	 * @param string $tableName table name | ||||
| 	 * @return array|boolean the loaded fixture rows indexed by row aliases (if any). | ||||
| 	 * False is returned if the table does not have a fixture. | ||||
| 	 * @throws InvalidConfigException if the specified table does not exist | ||||
| 	 */ | ||||
| 	public function loadFixture($tableName) | ||||
| 	{ | ||||
| 		$table = $this->db->getSchema()->getTableSchema($tableName); | ||||
| 		if ($table === null) { | ||||
| 			throw new InvalidConfigException("Table does not exist: $tableName"); | ||||
| 		} | ||||
| 
 | ||||
| 		$this->db->createCommand()->truncateTable($tableName); | ||||
| 
 | ||||
| 		$fileName = $this->basePath . '/' . $tableName . '.php'; | ||||
| 		if (!is_file($fileName)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		$rows = []; | ||||
| 		foreach (require($fileName) as $alias => $row) { | ||||
| 			$this->db->createCommand()->insert($tableName, $row)->execute(); | ||||
| 			if ($table->sequenceName !== null) { | ||||
| 				foreach ($table->primaryKey as $pk) { | ||||
| 					if (!isset($row[$pk])) { | ||||
| 						$row[$pk] = $this->db->getLastInsertID($table->sequenceName); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			$rows[$alias] = $row; | ||||
| 		} | ||||
| 
 | ||||
| 		return $rows; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the fixture data rows. | ||||
| 	 * The rows will have updated primary key values if the primary key is auto-incremental. | ||||
| 	 * @param string $fixtureName the fixture name | ||||
| 	 * @return array the fixture data rows. False is returned if there is no such fixture data. | ||||
| 	 */ | ||||
| 	public function getRows($fixtureName) | ||||
| 	{ | ||||
| 		return isset($this->_rows[$fixtureName]) ? $this->_rows[$fixtureName] : false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the specified ActiveRecord instance in the fixture data. | ||||
| 	 * @param string $fixtureName the fixture name | ||||
| 	 * @param string $modelName the alias for the fixture data row | ||||
| 	 * @return \yii\db\ActiveRecord the ActiveRecord instance. Null is returned if there is no such fixture row. | ||||
| 	 */ | ||||
| 	public function getModel($fixtureName, $modelName) | ||||
| 	{ | ||||
| 		if (!isset($this->_modelClasses[$fixtureName]) || !isset($this->_rows[$fixtureName][$modelName])) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		if (isset($this->_models[$fixtureName][$modelName])) { | ||||
| 			return $this->_models[$fixtureName][$modelName]; | ||||
| 		} | ||||
| 		$row = $this->_rows[$fixtureName][$modelName]; | ||||
| 		/** @var \yii\db\ActiveRecord $modelClass */ | ||||
| 		$modelClass = $this->_models[$fixtureName]; | ||||
| 		/** @var \yii\db\ActiveRecord $model */ | ||||
| 		$model = new $modelClass; | ||||
| 		$keys = []; | ||||
| 		foreach ($model->primaryKey() as $key) { | ||||
| 			$keys[$key] = isset($row[$key]) ? $row[$key] : null; | ||||
| 		} | ||||
| 		return $this->_models[$fixtureName][$modelName] = $modelClass::find($keys); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Enables or disables database integrity check. | ||||
| 	 * This method may be used to temporarily turn off foreign constraints check. | ||||
| 	 * @param boolean $check whether to enable database integrity check | ||||
| 	 */ | ||||
| 	public function checkIntegrity($check) | ||||
| 	{ | ||||
| 		foreach ($this->schemas as $schema) { | ||||
| 			$this->db->createCommand()->checkIntegrity($check, $schema); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,110 @@ | ||||
| <?php | ||||
| /** | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\test; | ||||
| 
 | ||||
| use Yii; | ||||
| 
 | ||||
| /** | ||||
|  * DbTestTrait implements the commonly used methods for setting up and accessing fixture data. | ||||
|  * | ||||
|  * To use DbTestTrait, call the [[loadFixtures()]] method in the setup method in a test case class. | ||||
|  * The specified fixtures will be loaded and accessible through [[getFixtureData()]] and [[getFixtureModel()]]. | ||||
|  * | ||||
|  * For example, | ||||
|  * | ||||
|  * ~~~ | ||||
|  * use yii\test\DbTestTrait; | ||||
|  * use app\models\Post; | ||||
|  * use app\models\User; | ||||
|  * | ||||
|  * class PostTestCase extends \PHPUnit_Framework_TestCase | ||||
|  * { | ||||
|  *     use DbTestTrait; | ||||
|  * | ||||
|  *     public function setUp() | ||||
|  *     { | ||||
|  *         $this->loadFixtures([ | ||||
|  *             'posts' => Post::className(), | ||||
|  *             'users' => User::className(), | ||||
|  *         ]); | ||||
|  *     } | ||||
|  * } | ||||
|  * ~~~ | ||||
|  * | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| trait DbTestTrait | ||||
| { | ||||
| 	/** | ||||
| 	 * Loads the specified fixtures. | ||||
| 	 * | ||||
| 	 * This method should typically be called in the setup method of test cases so that | ||||
| 	 * the fixtures are loaded before running each test method. | ||||
| 	 * | ||||
| 	 * This method does the following things: | ||||
| 	 * | ||||
| 	 * - Run [[DbFixtureManager::initScript]] if it is found under [[DbFixtureManager::basePath]]. | ||||
| 	 * - Clean up data and models loaded in memory previously. | ||||
| 	 * - Load each specified fixture: | ||||
| 	 *      * Truncate the corresponding table. | ||||
| 	 *      * If a fixture file named `TableName.php` is found under [[DbFixtureManager::basePath]], | ||||
| 	 *        the file will be executed, and the return value will be treated as rows which will | ||||
| 	 *        then be inserted into the table. | ||||
| 	 * | ||||
| 	 * @param array $fixtures a list of fixtures (fixture name => table name or AR class name) to be loaded. | ||||
| 	 * Each array element can be either a table name (with schema prefix if needed), or a fully-qualified | ||||
| 	 * ActiveRecord class name (e.g. `app\models\Post`). An element can be optionally associated with a key | ||||
| 	 * which will be treated as the fixture name. For example, | ||||
| 	 * | ||||
| 	 * ~~~ | ||||
| 	 * [ | ||||
| 	 *     'tbl_comment', | ||||
| 	 *     'users' => 'tbl_user',   // 'users' is the fixture name, 'tbl_user' is a table name | ||||
| 	 *     'posts' => 'app\models\Post,  // 'app\models\Post' is a model class name | ||||
| 	 * ] | ||||
| 	 * ~~~ | ||||
| 	 * | ||||
| 	 * @return array the loaded fixture data (fixture name => table rows) | ||||
| 	 */ | ||||
| 	public function loadFixtures(array $fixtures = []) | ||||
| 	{ | ||||
| 		return $this->getFixtureManager()->load($fixtures); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the DB fixture manager. | ||||
| 	 * @return DbFixtureManager the DB fixture manager | ||||
| 	 */ | ||||
| 	public function getFixtureManager() | ||||
| 	{ | ||||
| 		return Yii::$app->getComponent('fixture'); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the table rows of the named fixture. | ||||
| 	 * @param string $fixtureName the fixture name. | ||||
| 	 * @return array the named fixture table rows. False is returned if there is no such fixture data. | ||||
| 	 */ | ||||
| 	public function getFixtureRows($fixtureName) | ||||
| 	{ | ||||
| 		return $this->getFixtureManager()->getRows($fixtureName); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the named AR instance corresponding to the named fixture. | ||||
| 	 * @param string $fixtureName the fixture name. | ||||
| 	 * @param string $modelName the name of the fixture data row | ||||
| 	 * @return \yii\db\ActiveRecord the named AR instance corresponding to the named fixture. | ||||
| 	 * Null is returned if there is no such fixture or the record cannot be found. | ||||
| 	 */ | ||||
| 	public function getFixtureModel($fixtureName, $modelName) | ||||
| 	{ | ||||
| 		return $this->getFixtureManager()->getModel($fixtureName, $modelName); | ||||
| 	} | ||||
| } | ||||
| @ -1,25 +0,0 @@ | ||||
| <?php | ||||
| /** | ||||
|  * TestCase class. | ||||
|  * | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\test; | ||||
| 
 | ||||
| require_once('PHPUnit/Runner/Version.php'); | ||||
| spl_autoload_unregister(['Yii', 'autoload']); | ||||
| require_once('PHPUnit/Autoload.php'); | ||||
| spl_autoload_register(['Yii', 'autoload']); // put yii's autoloader at the end | ||||
| 
 | ||||
| /** | ||||
|  * TestCase is the base class for all test case classes. | ||||
|  * | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| abstract class TestCase extends \PHPUnit_Framework_TestCase | ||||
| { | ||||
| } | ||||
| @ -1,25 +0,0 @@ | ||||
| <?php | ||||
| /** | ||||
|  * WebTestCase class. | ||||
|  * | ||||
|  * @link http://www.yiiframework.com/ | ||||
|  * @copyright Copyright (c) 2008 Yii Software LLC | ||||
|  * @license http://www.yiiframework.com/license/ | ||||
|  */ | ||||
| 
 | ||||
| namespace yii\test; | ||||
| 
 | ||||
| require_once('PHPUnit/Runner/Version.php'); | ||||
| spl_autoload_unregister(['Yii','autoload']); | ||||
| require_once('PHPUnit/Autoload.php'); | ||||
| spl_autoload_register(['Yii','autoload']); // put yii's autoloader at the end | ||||
| 
 | ||||
| /** | ||||
|  * WebTestCase is the base class for all test case classes. | ||||
|  * | ||||
|  * @author Qiang Xue <qiang.xue@gmail.com> | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| abstract class WebTestCase extends \PHPUnit_Extensions_SeleniumTestCase | ||||
| { | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue