Dmitry Naumenko
8 years ago
2 changed files with 428 additions and 0 deletions
@ -0,0 +1,49 @@
|
||||
Preparación del entorno de test |
||||
=============================== |
||||
|
||||
> Note: Esta sección se encuentra en desarrollo. |
||||
|
||||
Yii 2 ha mantenido integración oficial con el framework de testing [`Codeception`](https://github.com/Codeception/Codeception), |
||||
que te permite crear los siguientes tipos de tests: |
||||
|
||||
- [Test de unidad](test-unit.md) - verifica que una unidad simple de código funciona como se espera; |
||||
- [Test funcional](test-functional.md) - verifica escenarios desde la perspectiva de un usuario a través de la emulación de un navegador; |
||||
- [Test de aceptación](test-acceptance.md) - verifica escenarios desde la perspectiva de un usuario en un navegador. |
||||
|
||||
Yii provee grupos de pruebas listos para utilizar en ambos |
||||
[`yii2-basic`](https://github.com/yiisoft/yii2-app-basic) y |
||||
[`yii2-advanced`](https://github.com/yiisoft/yii2-app-advanced) templates de proyectos. |
||||
|
||||
Para poder ejecutar estos tests es necesario instalar [Codeception](https://github.com/Codeception/Codeception). |
||||
Puedes instalarlo tanto localmente - únicamente para un proyecto en particular, o globalmente - para tu máquina de desarrollo. |
||||
|
||||
Para la instalación local utiliza los siguientes comandos: |
||||
|
||||
``` |
||||
composer require "codeception/codeception=2.1.*" |
||||
composer require "codeception/specify=*" |
||||
composer require "codeception/verify=*" |
||||
``` |
||||
|
||||
Para la instalación global necesitarás la directiva `global`: |
||||
|
||||
``` |
||||
composer global require "codeception/codeception=2.1.*" |
||||
composer global require "codeception/specify=*" |
||||
composer global require "codeception/verify=*" |
||||
``` |
||||
|
||||
En caso de que nunca hayas utilizado Composer para paquetes globales, ejecuta `composer global status`. Esto debería mostrar la salida: |
||||
|
||||
``` |
||||
Changed current directory to <directory> |
||||
``` |
||||
|
||||
Entonces agrega `<directory>/vendor/bin` a tu variable de entorno `PATH`. Ahora podrás utilizar el `codecept` en la línea |
||||
de comandos a nivel global. |
||||
|
||||
> Note: la instalación global te permite usar Codeception para todos los proyectos en los que trabajes en tu máquina de desarrollo y |
||||
te permite ejecutar el comando `codecept` globalmente sin especificar su ruta. De todos modos, ese acercamiento podría ser inapropiado, |
||||
por ejemplo, si 2 proyectos diferentes requieren diferentes versiones de Codeception instaladas. |
||||
Por simplicidad, todos los comandos relacionados a tests en esta guía están escritos asumiendo que Codeception |
||||
ha sido instalado en forma global. |
@ -0,0 +1,379 @@
|
||||
Fixtures |
||||
======== |
||||
|
||||
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. |
||||
|
||||
|
||||
Definir un Fixture |
||||
------------------ |
||||
|
||||
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 |
||||
<?php |
||||
namespace app\tests\fixtures; |
||||
|
||||
use yii\test\ActiveFixture; |
||||
|
||||
class UserFixture extends ActiveFixture |
||||
{ |
||||
public $modelClass = 'app\models\User'; |
||||
} |
||||
``` |
||||
|
||||
> Tip: 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 clase `ActiveRecord` especificada en `modelClass`. |
||||
|
||||
> Note: [[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 |
||||
<?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. |
||||
|
||||
> Tip: 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, |
||||
|
||||
```php |
||||
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 [[yii\test\Fixture::load()|load()]] y [[yii\test\Fixture::unload()|unload()]]. |
||||
|
||||
|
||||
Utilizar Fixtures |
||||
----------------- |
||||
|
||||
Si estás utilizando [Codeception](http://codeception.com/) 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 [[yii\test\FixtureTrait::fixtures()|fixtures()]]. Por ejemplo, |
||||
|
||||
```php |
||||
namespace app\tests\unit\models; |
||||
|
||||
use yii\codeception\DbTestCase; |
||||
use app\tests\fixtures\UserProfileFixture; |
||||
|
||||
class UserProfileTest extends DbTestCase |
||||
{ |
||||
public function fixtures() |
||||
{ |
||||
return [ |
||||
'profiles' => UserProfileFixture::className(), |
||||
]; |
||||
} |
||||
|
||||
// ...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: |
||||
|
||||
```php |
||||
// 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) ... |
||||
``` |
||||
|
||||
> Info: `$this->profiles` es todavía del tipo `UserProfileFixture`. Las características de acceso mostradas arriba son implementadas |
||||
> a través de métodos mágicos de PHP. |
||||
|
||||
|
||||
Definir y Utilizar Fixtures Globales |
||||
------------------------------------ |
||||
|
||||
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: |
||||
|
||||
* Realiza alguna tarea de inicialización común al ejectutar un script ubicado en `@app/tests/fixtures/initdb.php`; |
||||
* Deshabilita la comprobación de integridad antes de cargar otros fixtures de BD, y la rehabilita después de que todos los fixtures son descargados. |
||||
|
||||
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. |
||||
|
||||
|
||||
Organizar Clases de Fixtures y Archivos de Datos |
||||
------------------------------------------------ |
||||
|
||||
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. |
||||
|
||||
> Note: 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. |
||||
|
||||
|
||||
Resumen |
||||
------- |
||||
|
||||
> Note: 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: |
||||
|
||||
1. Usa la herramienta `yii migrate` para actualizar tu base de datos de prueba a la última versión; |
||||
2. Corre el caso de test: |
||||
- Carga los fixtures: limpia las tablas de la BD relevantes y cargala con los datos de los fixtures; |
||||
- Realiza el test en sí; |
||||
- Descarga los fixtures. |
||||
3. Repite el Paso 2 hasta que todos los tests terminen. |
||||
|
||||
|
||||
**Lo siguiente, a ser limpiado** |
||||
|
||||
Administrar Fixtures |
||||
==================== |
||||
|
||||
> Note: 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: |
||||
|
||||
* Cargar fixtures a diferentes almacenamientos: RDBMS, NoSQL, etc; |
||||
* Descargar fixtures de diferentes maneras (usualmente limpiando el almacenamiento); |
||||
* Auto-generar fixtures y poblarlos con datos al azar. |
||||
|
||||
Formato de Fixtures |
||||
------------------- |
||||
|
||||
Los fixtures son objetos con diferentes métodos y configuraciones, inspecciónalos en la [documentación oficial](https://github.com/yiisoft/yii2/blob/master/docs/guide-es/test-fixtures.md). |
||||
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](https://github.com/yiisoft/yii2/blob/master/docs/guide-es/test-fixtures.md). |
||||
El fixture de ejemplo de arriba fue autogenerado por la extensión `yii2-faker`, lee más acerca de esto en su [sección](#auto-generating-fixtures). |
||||
Los nombres de clase de fixtures no deberían ser en plural. |
||||
|
||||
Cargar fixtures |
||||
---------------- |
||||
|
||||
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' |
||||
``` |
||||
|
||||
Descargar fixtures |
||||
------------------ |
||||
|
||||
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. |
||||
|
||||
Configurar el Comando Globalmente |
||||
--------------------------------- |
||||
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' |
||||
], |
||||
], |
||||
] |
||||
``` |
||||
|
||||
Autogenerando fixtures |
||||
---------------------- |
||||
|
||||
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](https://github.com/fzaninotto/Faker) y la extensión `yii2-faker`. |
||||
Visita la [guía de la extensión](https://github.com/yiisoft/yii2-faker) para mayor documentación. |
Loading…
Reference in new issue