Los fixtures son una parte importante de los tests. Su propósito principal es el de preparar el entorno en una estado fijado/conocido de manera que los tests sean repetibles y corran de la manera esperada. Yii provee un framework de fixtures que te permite dichos fixtures de manera precisa y usarlo de forma simple.
Un concepto clave en el framework de fixtures de Yii es el llamado objeto fixture. Un objeto fixture representa
un aspecto particular de un entorno de pruebas y es una instancia de yii\test\Fixture o heredada de esta. Por ejemplo,
puedes utilizar UserFixture
para asegurarte de que la tabla de usuarios de la BD contiene un grupo de datos fijos. Entonces cargas uno o varios
objetos fixture antes de correr un test y lo descargas cuando el test ha concluido.
Un fixture puede depender de otros fixtures, especificándolo en su propiedad yii\test\Fixture::$depends. Cuando un fixture está siendo cargado, los fixtures de los que depende serán cargados automáticamente ANTES que él; y cuando el fixture está siendo descargado, los fixtures dependientes serán descargados DESPUÉS de él.
Para definir un fixture, crea una nueva clase que extienda de yii\test\Fixture o yii\test\ActiveFixture. El primero es más adecuado para fixtures de propósito general, mientras que el último tiene características mejoradas específicamente diseñadas para trabajar con base de datos y ActiveRecord.
El siguiente código define un fixture acerca del ActiveRecord User
y su correspondiente tabla user.
<?php
namespace app\tests\fixtures;
use yii\test\ActiveFixture;
class UserFixture extends ActiveFixture
{
public $modelClass = 'app\models\User';
}
Consejo: Cada
ActiveFixture
se encarga de preparar la tabla de la DB para los tests. Puedes especificar la tabla definiendo tanto la propiedad yii\test\ActiveFixture::$tableName o la propiedad yii\test\ActiveFixture::$modelClass. Haciéndolo como el último, el nombre de la tabla será tomado de la claseActiveRecord
especificada enmodelClass
.
Nota: yii\test\ActiveFixture es sólo adecualdo para bases de datos SQL. Para bases de datos NoSQL, Yii provee las siguientes clases
ActiveFixture
:
- Mongo DB: yii\mongodb\ActiveFixture
- Elasticsearch: yii\elasticsearch\ActiveFixture (desde la versión 2.0.2)
Los datos para un fixture ActiveFixture
son usualmente provistos en un archivo ubicado en FixturePath/data/TableName.php
,
donde FixturePath
corresponde al directorio conteniendo el archivo de clase del fixture, y TableName
es el nombre de la tabla asociada al fixture. En el ejemplo anterior, el archivo debería ser
@app/tests/fixtures/data/user.php
. El archivo de datos debe devolver un array de registros
a ser insertados en la tabla user. Por ejemplo,
<?php
return [
'user1' => [
'username' => 'lmayert',
'email' => 'strosin.vernice@jerde.com',
'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
],
'user2' => [
'username' => 'napoleon69',
'email' => 'aileen.barton@heaneyschumm.com',
'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
],
];
Puedes dar un alias al registro tal que más tarde en tu test, puedas referirte a ese registra a través de dicho alias. En el ejemplo anterior,
los dos registros tienen como alias user1
y user2
, respectivamente.
Además, no necesitas especificar los datos de columnas auto-incrementales. Yii automáticamente llenará esos valores dentro de los registros cuando el fixture está siendo cargado.
Consejo: Puedes personalizar la ubicación del archivo de datos definiendo la propiedad yii\test\ActiveFixture::$dataFile. Puedes también sobrescribir yii\test\ActiveFixture::getData() para obtener los datos.
Como se describió anteriormente, un fixture puede depender de otros fixtures. Por ejemplo, un UserProfileFixture
puede necesitar depender de UserFixture
porque la table de perfiles de usuarios contiene una clave foránea a la tabla user.
La dependencia es especificada vía la propiedad yii\test\Fixture::$depends, como a continuación,
namespace app\tests\fixtures;
use yii\test\ActiveFixture;
class UserProfileFixture extends ActiveFixture
{
public $modelClass = 'app\models\UserProfile';
public $depends = ['app\tests\fixtures\UserFixture'];
}
La dependencia también asegura que los fixtures son cargados y descargados en un orden bien definido. En el ejemplo UserFixture
será siempre cargado antes de UserProfileFixture
para asegurar que todas las referencias de las claves foráneas existan y será siempre descargado después de UserProfileFixture
por la misma razón.
Arriba te mostramos cómo definir un fixture de BD. Para definir un fixture no relacionado a BD (por ej. un fixture acerca de archivos y directorios), puedes extender de la clase base más general yii\test\Fixture y sobrescribir los métodos load() y unload().
Si estás utilizando Codeception para hacer tests de tu código, deberías considerar el utilizar
la extensión yii2-codeception
, que tiene soporte incorporado para la carga y acceso a fixtures.
En caso de que utilices otros frameworks de testing, puedes usar yii\test\FixtureTrait en tus casos de tests
para alcanzar el mismo objetivo.
A continuación describiremos cómo escribir una clase de test de unidad UserProfile
utilizando yii2-codeception
.
En tu clase de test de unidad que extiende de yii\codeception\DbTestCase o yii\codeception\TestCase, indica cuáles fixtures quieres utilizar en el método fixtures(). Por ejemplo,
namespace app\tests\unit\models;
use yii\codeception\DbTestCase;
use app\tests\fixtures\UserProfileFixture;
class UserProfileTest extends DbTestCase
{
public function fixtures()
{
return [
'profiles' => UserProfileFixture::class,
];
}
// ...métodos de test...
}
Los fixtures listados en el método fixtures()
serán automáticamente cargados antes de correr cada método de test
en el caso de test y descargado al finalizar cada uno. También, como describimos antes, cuando un fixture está
siendo cargado, todos sus fixtures dependientes serán cargados primero. En el ejemplo de arriba, debido a que
UserProfileFixture
depende de UserFixture
, cuando ejecutas cualquier método de test en la clase,
dos fixtures serán cargados secuencialmente: UserFixture
y UserProfileFixture
.
Al especificar fixtures en fixtures()
, puedes utilizar tanto un nombre de clase o un array de configuración para referirte a
un fixture. El array de configuración te permitirá personalizar las propiedades del fixture cuando este es cargado.
Puedes también asignarles alias a los fixtures. En el ejemplo anterior, el UserProfileFixture
tiene como alias profiles
.
En los métodos de test, puedes acceder a un objeto fixture utilizando su alias. Por ejemplo, $this->profiles
devolverá el objeto UserProfileFixture
.
Dado que UserProfileFixture
extiende de ActiveFixture
, puedes por lo tanto usar la siguiente sintáxis para acceder
a los datos provistos por el fixture:
// devuelve el registro del fixture cuyo alias es 'user1'
$row = $this->profiles['user1'];
// devuelve el modelo UserProfile correspondiente al registro cuyo alias es 'user1'
$profile = $this->profiles('user1');
// recorre cada registro en el fixture
foreach ($this->profiles as $row) ...
Información:
$this->profiles
es todavía del tipoUserProfileFixture
. Las características de acceso mostradas arriba son implementadas a través de métodos mágicos de PHP.
Los fixtures descritos arriba son principalmente utilizados para casos de tests individuales. En la mayoría de los casos, puedes necesitar algunos fixtures globales que sean aplicados a TODOS o muchos casos de test. Un ejemplo sería yii\test\InitDbFixture, que hace dos cosas:
@app/tests/fixtures/initdb.php
;Utilizar fixtures globales es similar a utilizar los no-globales. La única diferencia es que declaras estos fixtures
en yii\codeception\TestCase::globalFixtures() en vez de en fixtures()
. Cuando un caso de test carga fixtures,
primero carga los globales y luego los no-globales.
Por defecto, yii\codeception\DbTestCase ya declara InitDbFixture
en su método globalFixtures()
.
Esto significa que sólo necesitas trabajar con @app/tests/fixtures/initdb.php
si quieres realizar algún trabajo de inicialización
antes de cada test. Sino puedes simplemente enfocarte en desarrollar cada caso de test individual y sus fixtures correspondientes.
Por defecto, las clases de fixtures busca los archivos de datos correspondientes dentro de la carpeta data
, que es una subcarpeta
de la carpeta conteniendo los archivos de clases de fixtures. Puedes seguir esta convención al trabajar en proyectos simples.
Para proyectos más grandes, es probable que a menudo necesites intercambiar entre diferentes archivos de datos para la misma clase de fixture
en diferentes tests. Recomendamos que organices los archivos de datos en forma jerárquica similar
a tus espacios de nombre de clases. Por ejemplo,
# bajo la carpeta tests\unit\fixtures
data\
components\
fixture_data_file1.php
fixture_data_file2.php
...
fixture_data_fileN.php
models\
fixture_data_file1.php
fixture_data_file2.php
...
fixture_data_fileN.php
# y así sucesivamente
De esta manera evitarás la colisión de archivos de datos de fixtures entre tests y podrás utlilizarlos como necesites.
Nota: En el ejemplo de arriba los archivos de fixtures son nombrados así sólo como ejemplo. En la vida real deberías nombrarlos de acuerdo a qué clase de fixture extienden tus clases de fixtures. Por ejemplo, si estás extendiendo de yii\test\ActiveFixture para fixtures de BD, deberías utilizar nombres de tabla de la BD como nombres de los archivos de fixtures; Si estás extendiendo de yii\mongodb\ActiveFixture para fixtures de MongoDB, deberías utilizar nombres de colecciones para los nombres de archivo.
Se puede utilizar una jerarquía similar para organizar archivos de clases de fixtures. En vez de utilizar data
como directorio raíz, podrías
querer utilizar fixtures
como directorio raíz para evitar conflictos con los archivos de datos.
Nota: Esta sección se encuentra en desarrollo.
Arriba, definimos cómo definir y utilizar fixtures. Abajo resumiremos el típico flujo de trabajo de correr tests de unidad relacionados a BD:
yii migrate
para actualizar tu base de datos de prueba a la última versión;Lo siguiente, a ser limpiado
Nota: Esta sección está en desarrollo.
todo: este tutorial podría ser unificado con la parte de arriba en test-fixtures.md
Los fixtures son una parte importante del testing. Su principal propósito es el de poblarte con datos necesarios para el test de diferentes casos. Con estos datos. utilizar tests se vuelve más eficiente y útil.
Yii soporta fixtures a través de la herramienta de línea de comandos yii fixture
. Esta herramienta soporta:
Los fixtures son objetos con diferentes métodos y configuraciones, inspecciónalos en la documentación oficial. Asumamos que tenemos datos de fixtures a cargar:
#archivo users.php bajo la ruta de los fixtures, por defecto @tests\unit\fixtures\data
return [
[
'name' => 'Chase',
'login' => 'lmayert',
'email' => 'strosin.vernice@jerde.com',
'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
],
[
'name' => 'Celestine',
'login' => 'napoleon69',
'email' => 'aileen.barton@heaneyschumm.com',
'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
],
];
Si estamos utilizando un fixture que carga datos en la base de datos, entonces esos registros serán insertados en la tabla users
. Si estamos utilizando fixtures no sql, por ejemplo de mongodb
,
entonces estos datos serán aplicados a la colección mongodb users
. Para aprender cómo implementar varias estrategias de carga y más, visita la documentación oficial.
El fixture de ejemplo de arriba fue autogenerado por la extensión yii2-faker
, lee más acerca de esto en su sección.
Los nombres de clase de fixtures no deberían ser en plural.
Las clases de fixture deberían tener el prefijo Fixture
. Por defecto los fixtures serán buscados bajo el espacio de nombre tests\unit\fixtures
, puedes
modificar este comportamiento con opciones de comando o configuración. Puedes excluir algunos fixtures para carga o descarga especificando -
antes de su nombre, por ejemplo -User
.
Para cargar un fixture, ejecuta el siguiente comando:
yii fixture/load <fixture_name>
El parámetro requerido fixture_name
especifica un nombre de fixture cuyos datos serán cargados. Puedes cargar varios fixtures de una sola vez.
Abajo se muestran formatos correctos de este comando:
// carga el fixture `User`
yii fixture/load User
// lo mismo que arriba, dado que la acción por defecto del comando "fixture" es "load"
yii fixture User
// carga varios fixtures
yii fixture "User, UserProfile"
// carga todos los fixtures
yii fixture/load "*"
// lo mismo que arriba
yii fixture "*"
// carga todos los fixtures excepto uno
yii fixture "*, -DoNotLoadThisOne"
// carga fixtures, pero los busca en diferente espacio de nombre. El espacio de nombre por defecto es: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'
// carga el fixture global `some\name\space\CustomFixture` antes de que otros fixtures sean cargados.
// Por defecto está opción se define como `InitDbFixture` para habilitar/deshabilitar la comprobación de integridad. Puedes especificar varios
// fixtures globales separados por coma.
yii fixture User --globalFixtures='some\name\space\Custom'
Para descargar un fixture, ejecuta el siguiente comando:
// descarga el fixture Users, por defecto limpiará el almacenamiento del fixture (por ejemplo la tabla "users", o la colección "users" si es un fixture mongodb).
yii fixture/unload User
// descarga varios fixtures
yii fixture/unload "User, UserProfile"
// descarga todos los fixtures
yii fixture/unload "*"
// descarga todos los fixtures excepto uno
yii fixture/unload "*, -DoNotUnloadThisOne"
Opciones de comando similares como: namespace
, globalFixtures
también pueden ser aplicadas a este comando.
Mientras que las opciones de línea de comandos nos permiten configurar el comando de migración en el momento, a veces queremos configurar el comando de una vez y para siempre. Por ejemplo puedes configurar diferentes rutas de migración como a continuación:
'controllerMap' => [
'fixture' => [
'class' => 'yii\console\controllers\FixtureController',
'namespace' => 'myalias\some\custom\namespace',
'globalFixtures' => [
'some\name\space\Foo',
'other\name\space\Bar'
],
],
]
Yii puede también autogenerar fixtures por tí basándose en algún template. Puedes generar tus fixtures con distintos datos en diferentes lenguajes y formatos.
Esta característica es realizada por la librería Faker y la extensión yii2-faker
.
Visita la guía de la extensión para mayor documentación.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.