Commit 4fd1d0e1 by maxmirazh33

Merge branch 'master' of git://github.com/yiisoft/yii2

parents 77effdbc f5ee8e45
......@@ -18,4 +18,4 @@ $_SERVER['SCRIPT_FILENAME'] = YII_TEST_BACKEND_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = YII_BACKEND_TEST_ENTRY_URL;
$_SERVER['SERVER_NAME'] = 'localhost';
Yii::setAlias('@codeception', dirname(__DIR__));
Yii::setAlias('@tests', dirname(dirname(__DIR__)));
......@@ -12,7 +12,7 @@ class_name: AcceptanceTester
modules:
enabled:
- PhpBrowser
- codeception\common\_support\FixtureHelper
- tests\codeception\common\_support\FixtureHelper
# you can use WebDriver instead of PhpBrowser to test javascript and ajax.
# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
# "restart" option is used by the WebDriver to start each time per test-file new session and cookies,
......
<?php
use codeception_backend\AcceptanceTester;
use codeception\common\_pages\LoginPage;
use tests\codeception\backend\AcceptanceTester;
use tests\codeception\common\_pages\LoginPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure login page works');
......
namespace: codeception_backend
namespace: tests\codeception\backend
actor: Tester
paths:
tests: .
......
......@@ -11,7 +11,7 @@ modules:
enabled:
- Filesystem
- Yii2
- codeception\common\_support\FixtureHelper
- tests\codeception\common\_support\FixtureHelper
config:
Yii2:
configFile: '../config/backend/functional.php'
<?php
use codeception_backend\FunctionalTester;
use codeception\common\_pages\LoginPage;
use tests\codeception\backend\FunctionalTester;
use tests\codeception\common\_pages\LoginPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure login page works');
......
......@@ -4,5 +4,5 @@ namespace backend\tests\unit;
class DbTestCase extends \yii\codeception\DbTestCase
{
public $appConfig = '@codeception/config/backend/unit.php';
public $appConfig = '@tests/codeception/config/backend/unit.php';
}
......@@ -4,5 +4,5 @@ namespace backend\tests\unit;
class TestCase extends \yii\codeception\TestCase
{
public $appConfig = '@codeception/config/backend/unit.php';
public $appConfig = '@tests/codeception/config/backend/unit.php';
}
......@@ -11,4 +11,4 @@ require(YII_APP_BASE_PATH . '/common/config/aliases.php');
// set correct script paths
$_SERVER['SERVER_NAME'] = 'localhost';
Yii::setAlias('@codeception', dirname(__DIR__));
\ No newline at end of file
Yii::setAlias('@tests', dirname(dirname(__DIR__)));
\ No newline at end of file
<?php
namespace codeception\common\_pages;
namespace tests\codeception\common\_pages;
use yii\codeception\BasePage;
......
<?php
namespace codeception\common\_support;
namespace tests\codeception\common\_support;
use codeception\common\fixtures\UserFixture;
use tests\codeception\common\fixtures\UserFixture;
use Codeception\Module;
use yii\test\FixtureTrait;
......@@ -53,7 +53,7 @@ class FixtureHelper extends Module
return [
'user' => [
'class' => UserFixture::className(),
'dataFile' => '@codeception/common/fixtures/data/init_login.php',
'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php',
],
];
}
......
namespace: codeception_common
namespace: tests\codeception\common
actor: Tester
paths:
tests: .
......
<?php
namespace codeception\common\fixtures;
namespace tests\codeception\common\fixtures;
use yii\test\ActiveFixture;
......
<?php
namespace codeception\common\unit;
namespace tests\codeception\common\unit;
/**
* @inheritdoc
*/
class DbTestCase extends \yii\codeception\DbTestCase
{
public $appConfig = '@codeception/config/common/unit.php';
public $appConfig = '@tests/codeception/config/common/unit.php';
}
<?php
namespace common\tests\unit;
namespace tests\codeception\common\unit;
/**
* @inheritdoc
*/
class TestCase extends \yii\codeception\TestCase
{
public $appConfig = '@codeception/config/common/unit.php';
public $appConfig = '@tests/codeception/config/common/unit.php';
}
<?php
namespace codeception\common\unit\models;
namespace tests\codeception\common\unit\models;
use Yii;
use codeception\common\unit\DbTestCase;
use tests\codeception\common\unit\DbTestCase;
use Codeception\Specify;
use common\models\LoginForm;
use codeception\common\fixtures\UserFixture;
use tests\codeception\common\fixtures\UserFixture;
/**
* Login form test
......@@ -86,7 +86,7 @@ class LoginFormTest extends DbTestCase
return [
'user' => [
'class' => UserFixture::className(),
'dataFile' => '@codeception/common/unit/fixtures/data/models/user.php'
'dataFile' => '@tests/codeception/common/unit/fixtures/data/models/user.php'
],
];
}
......
<?php
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(dirname(__DIR__)))));
/**
* Application configuration for backend acceptance tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/common/config/main.php'),
require(YII_APP_BASE_PATH . '/common/config/main-local.php'),
......
<?php
/**
* Application configuration for all backend test types
*/
return [];
\ No newline at end of file
......@@ -2,6 +2,9 @@
$_SERVER['SCRIPT_FILENAME'] = YII_TEST_BACKEND_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = YII_BACKEND_TEST_ENTRY_URL;
/**
* Application configuration for backend functional tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/backend/config/main.php'),
require(YII_APP_BASE_PATH . '/backend/config/main-local.php'),
......
<?php
/**
* Application configuration for backend unit tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/common/config/main.php'),
require(YII_APP_BASE_PATH . '/common/config/main-local.php'),
......
<?php
/**
* Application configuration for console unit tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/common/config/main.php'),
require(YII_APP_BASE_PATH . '/common/config/main-local.php'),
......
<?php
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(dirname(__DIR__)))));
/**
* Application configuration for frontend acceptance tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/common/config/main.php'),
require(YII_APP_BASE_PATH . '/common/config/main-local.php'),
......
<?php
/**
* Application configuration for all frontend test types
*/
return [];
\ No newline at end of file
......@@ -2,6 +2,9 @@
$_SERVER['SCRIPT_FILENAME'] = FRONTEND_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = FRONTEND_ENTRY_URL;
/**
* Application configuration for frontend functional tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/common/config/main.php'),
require(YII_APP_BASE_PATH . '/common/config/main-local.php'),
......
<?php
/**
* Application configuration for frontend unit tests
*/
return yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/common/config/main.php'),
require(YII_APP_BASE_PATH . '/common/config/main-local.php'),
......
......@@ -11,4 +11,4 @@ require(YII_APP_BASE_PATH . '/common/config/aliases.php');
// set correct script paths
$_SERVER['SERVER_NAME'] = 'localhost';
Yii::setAlias('@codeception', dirname(__DIR__));
\ No newline at end of file
Yii::setAlias('@tests', dirname(dirname(__DIR__)));
\ No newline at end of file
namespace: codeception_console
namespace: tests\codeception\console
actor: Tester
paths:
tests: .
......
<?php
namespace console\tests\unit;
namespace tests\codeception\console\unit;
/**
* @inheritdoc
*/
class DbTestCase extends \yii\codeception\DbTestCase
{
public $appConfig = '@codeception/config/console/config.php';
public $appConfig = '@tests/codeception/config/console/config.php';
}
<?php
namespace console\tests\unit;
namespace tests\codeception\console\unit;
/**
* @inheritdoc
*/
class TestCase extends \yii\codeception\TestCase
{
public $appConfig = '@codeception/config/console/config.php';
public $appConfig = '@tests/codeception/config/console/config.php';
}
......@@ -18,4 +18,4 @@ $_SERVER['SCRIPT_FILENAME'] = FRONTEND_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = FRONTEND_ENTRY_URL;
$_SERVER['SERVER_NAME'] = 'localhost';
Yii::setAlias('@codeception', dirname(__DIR__));
\ No newline at end of file
Yii::setAlias('@tests', dirname(dirname(__DIR__)));
\ No newline at end of file
<?php
namespace codeception\frontend\_pages;
namespace tests\codeception\frontend\_pages;
use yii\codeception\BasePage;
......
<?php
namespace codeception\frontend\_pages;
namespace tests\codeception\frontend\_pages;
use yii\codeception\BasePage;
......
<?php
namespace codeception\frontend\_pages;
namespace tests\codeception\frontend\_pages;
use \yii\codeception\BasePage;
......
......@@ -12,7 +12,7 @@ class_name: AcceptanceTester
modules:
enabled:
- PhpBrowser
- codeception\common\_support\FixtureHelper
- tests\codeception\common\_support\FixtureHelper
# you can use WebDriver instead of PhpBrowser to test javascript and ajax.
# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
# "restart" option is used by the WebDriver to start each time per test-file new session and cookies,
......
<?php
use codeception_frontend\AcceptanceTester;
use codeception\frontend\_pages\AboutPage;
use tests\codeception\frontend\AcceptanceTester;
use tests\codeception\frontend\_pages\AboutPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that about works');
......
<?php
use codeception_frontend\AcceptanceTester;
use codeception\frontend\_pages\ContactPage;
use tests\codeception\frontend\AcceptanceTester;
use tests\codeception\frontend\_pages\ContactPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that contact works');
......
<?php
use codeception_frontend\AcceptanceTester;
use tests\codeception\frontend\AcceptanceTester;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that home page works');
......
<?php
use codeception_frontend\AcceptanceTester;
use codeception\common\_pages\LoginPage;
use tests\codeception\frontend\AcceptanceTester;
use tests\codeception\common\_pages\LoginPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure login page works');
......
<?php
namespace codeception\frontend\acceptance;
namespace tests\codeception\frontend\acceptance;
use codeception\frontend\_pages\SignupPage;
use tests\codeception\frontend\_pages\SignupPage;
use common\models\User;
class SignupCest
......
namespace: codeception_frontend
namespace: tests\codeception\frontend
actor: Tester
paths:
tests: .
......
......@@ -11,7 +11,7 @@ modules:
enabled:
- Filesystem
- Yii2
- codeception\common\_support\FixtureHelper
- tests\codeception\common\_support\FixtureHelper
config:
Yii2:
configFile: '../config/frontend/functional.php'
<?php
use codeception_frontend\FunctionalTester;
use codeception\frontend\_pages\AboutPage;
use tests\codeception\frontend\FunctionalTester;
use tests\codeception\frontend\_pages\AboutPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure that about works');
......
<?php
use codeception_frontend\FunctionalTester;
use codeception\frontend\_pages\ContactPage;
use tests\codeception\frontend\FunctionalTester;
use tests\codeception\frontend\_pages\ContactPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure that contact works');
......
<?php
use codeception_frontend\FunctionalTester;
use tests\codeception\frontend\FunctionalTester;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure that home page works');
$I->amOnPage(Yii::$app->homeUrl);
......
<?php
use codeception_frontend\FunctionalTester;
use codeception\common\_pages\LoginPage;
use tests\codeception\frontend\FunctionalTester;
use tests\codeception\common\_pages\LoginPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure login page works');
......
<?php
namespace codeception\frontend\functional;
namespace tests\codeception\frontend\functional;
use codeception\frontend\_pages\SignupPage;
use tests\codeception\frontend\_pages\SignupPage;
use common\models\User;
class SignupCest
......
<?php
namespace codeception\frontend\unit;
namespace tests\codeception\frontend\unit;
/**
* @inheritdoc
*/
class DbTestCase extends \yii\codeception\DbTestCase
{
public $appConfig = '@codeception/config/frontend/unit.php';
public $appConfig = '@tests/codeception/config/frontend/unit.php';
}
<?php
namespace codeception\frontend\unit;
namespace tests\codeception\frontend\unit;
/**
* @inheritdoc
*/
class TestCase extends \yii\codeception\TestCase
{
public $appConfig = '@codeception/config/frontend/unit.php';
public $appConfig = '@tests/codeception/config/frontend/unit.php';
}
<?php
namespace codeception\frontend\unit\models;
namespace tests\codeception\frontend\unit\models;
use Yii;
use codeception\frontend\unit\TestCase;
use tests\codeception\frontend\unit\TestCase;
use frontend\models\ContactForm;
class ContactFormTest extends TestCase
......
<?php
namespace codeception\frontend\tests\models;
namespace tests\codeception\frontend\models;
use Yii;
use codeception\frontend\unit\DbTestCase;
use tests\codeception\frontend\unit\DbTestCase;
use frontend\models\PasswordResetRequestForm;
use codeception\common\fixtures\UserFixture;
use tests\codeception\common\fixtures\UserFixture;
use common\models\User;
use Codeception\Specify;
......@@ -75,7 +75,7 @@ class PasswordResetRequestFormTest extends DbTestCase
return [
'user' => [
'class' => UserFixture::className(),
'dataFile' => '@codeception/frontend/unit/fixtures/data/models/user.php'
'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'
],
];
}
......
<?php
namespace codeception\frontend\unit\models;
namespace tests\codeception\frontend\unit\models;
use codeception\frontend\unit\DbTestCase;
use codeception\common\fixtures\UserFixture;
use tests\codeception\frontend\unit\DbTestCase;
use tests\codeception\common\fixtures\UserFixture;
use frontend\models\ResetPasswordForm;
class ResetPasswordFormTest extends DbTestCase
......@@ -36,7 +36,7 @@ class ResetPasswordFormTest extends DbTestCase
return [
'user' => [
'class' => UserFixture::className(),
'dataFile' => '@codeception/frontend/unit/fixtures/data/models/user.php'
'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'
],
];
}
......
<?php
namespace codeception\frontend\unit\models;
namespace tests\codeception\frontend\unit\models;
use codeception\frontend\unit\DbTestCase;
use codeception\common\fixtures\UserFixture;
use tests\codeception\frontend\unit\DbTestCase;
use tests\codeception\common\fixtures\UserFixture;
use Codeception\Specify;
use frontend\models\SignupForm;
......@@ -45,7 +45,7 @@ class SignupFormTest extends DbTestCase
return [
'user' => [
'class' => UserFixture::className(),
'dataFile' => '@codeception/frontend/unit/fixtures/data/models/user.php',
'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php',
],
];
}
......
......@@ -21,20 +21,40 @@ Changed current directory to <directory>
Then add `<directory>/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command
line globally.
2. Build the test suites:
2. Install faker extension by running the following from template root directory where `composer.json` is:
```
composer require --dev yiisoft/yii2-faker:*
```
3. Create three databases that are used in tests:
* `yii2_basic_unit` - for unit tests;
* `yii2_basic_functional` - for functional tests;
* `yii2_basic_acceptance` - for acceptance tests.
Then update databases by applying migrations:
```
codeception/bin/yii_acceptance migrate
codeception/bin/yii_functional migrate
codeception/bin/yii_unit migrate
```
4. Build the test suites:
```
codecept build
```
3. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in
5. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in
webserver. In the `web` directory execute the following:
```
php -S localhost:8080
```
4. Now you can run the tests with the following commands:
6. Now you can run the tests with the following commands:
```
# run all available tests
......
......@@ -12,4 +12,4 @@ $_SERVER['SCRIPT_FILENAME'] = YII_TEST_ENTRY_FILE;
$_SERVER['SCRIPT_NAME'] = YII_TEST_ENTRY_URL;
$_SERVER['SERVER_NAME'] = 'localhost';
Yii::setAlias('@codeception', __DIR__);
Yii::setAlias('@tests', dirname(__DIR__));
<?php
namespace codeception\_pages;
namespace tests\codeception\_pages;
use yii\codeception\BasePage;
......
<?php
namespace codeception\_pages;
namespace tests\codeception\_pages;
use yii\codeception\BasePage;
......
<?php
namespace codeception\_pages;
namespace tests\codeception\_pages;
use yii\codeception\BasePage;
......
<?php
use codeception\_pages\AboutPage;
use tests\codeception\_pages\AboutPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that about works');
......
<?php
use codeception\_pages\ContactPage;
use tests\codeception\_pages\ContactPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that contact works');
......
<?php
use codeception\_pages\LoginPage;
use tests\codeception\_pages\LoginPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that login works');
......
......@@ -14,6 +14,13 @@ $config = yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/config/console.php'),
require(__DIR__ . '/../config/config.php'),
[
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => dirname(__DIR__) . 'fixtures',
'templatePath' => dirname(__DIR__) . 'templates'
],
],
'components' => [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=yii2_basic_acceptance',
......
......@@ -14,6 +14,13 @@ $config = yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/config/console.php'),
require(__DIR__ . '/../config/config.php'),
[
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => dirname(__DIR__) . 'fixtures',
'templatePath' => dirname(__DIR__) . 'templates'
],
],
'components' => [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=yii2_basic_functional',
......
......@@ -14,6 +14,13 @@ $config = yii\helpers\ArrayHelper::merge(
require(YII_APP_BASE_PATH . '/config/console.php'),
require(__DIR__ . '/../config/config.php'),
[
'controllerMap' => [
'fixture' => [
'class' => 'yii\faker\FixtureController',
'fixtureDataPath' => dirname(__DIR__) . 'fixtures',
'templatePath' => dirname(__DIR__) . 'templates'
],
],
'components' => [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=yii2_basic_unit',
......
*
!.gitignore
\ No newline at end of file
<?php
use codeception\_pages\AboutPage;
use tests\codeception\_pages\AboutPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure that about works');
......
<?php
use codeception\_pages\ContactPage;
use tests\codeception\_pages\ContactPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure that contact works');
......
<?php
use codeception\_pages\LoginPage;
use tests\codeception\_pages\LoginPage;
$I = new FunctionalTester($scenario);
$I->wantTo('ensure that login works');
......
*
!.gitignore
\ No newline at end of file
<?php
namespace codeception\unit\models;
namespace tests\codeception\unit\models;
use Yii;
use yii\codeception\TestCase;
......
<?php
namespace codeception\unit\models;
namespace tests\codeception\unit\models;
use Yii;
use yii\codeception\TestCase;
......
<?php
namespace codeception\unit\models;
namespace tests\codeception\unit\models;
use yii\codeception\TestCase;
......
......@@ -151,6 +151,7 @@ Testing
-------
* [Overview](test-overview.md)
* [Testing environment setup](test-endvironment-setup.md)
* [Unit Tests](test-unit.md)
* [Functional Tests](test-functional.md)
* [Acceptance Tests](test-acceptance.md)
......
......@@ -293,7 +293,7 @@ line:
migration history information. It defaults to `migration`. The table
structure is `version varchar(255) primary key, apply_time integer`.
* `connectionID`: string, specifies the ID of the database application component.
* `db`: string, specifies the ID of the database application component.
Defaults to 'db'.
* `templateFile`: string, specifies the path of the file to be served as the code
......@@ -337,3 +337,45 @@ the console application's configuration file like the following,
Now if we run the `migrate` command, the above configurations will take effect
without requiring us to enter the command line options every time. Other command options
can be also configured this way.
### Migrating with Multiple Databases
By default, migrations will be applied to the database specified by the `db` application component.
You may change it by specifying the `--db` option, for example,
```
yii migrate --db=db2
```
The above command will apply *all* migrations found in the default migration path to the `db2` database.
If your application works with multiple databases, some migrations should be applied to one database while
some others should be applied to another database. In this case, it is recommended that you create a base
migration class for each different database and override the [[yii\db\Migration::init()]] method like the following,
```php
public function init()
{
$this->db = 'db2';
parent::init();
}
```
If a migration needs to be applied to one database, you create a migration class by extending from the corresponding
base migration class.
Now if you run the `yii migrate` command, each migration will be applied to the corresponding database.
Because each migration has harcoded the DB connection, the `--db` option of the `migrate` command will have no effect.
If you still want to support changing DB connection via the `--db` option, you may take the following alternative
approach to work with multiple databases.
For each database, create a migration path and save all corresponding migration classes there. To apply migrations,
run the command as follows,
```
yii migrate --migrationPath=@app/migrations/db1 --db=db1
yii migrate --migrationPath=@app/migrations/db2 --db=db2
...
```
Versioning
==========
Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side
code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward
compatibility (BC) of the APIs should be maintained whenever possible, and if some BC-breaking changes must be
introduced to the APIs, you should bump up the version number. You may refer to [Semantic Versioning](http://semver.org/)
for more information about designing the version numbers of your APIs.
A good API is *versioned*: changes and new features are implemented in new versions of the API instead of continually altering just one version. Unlike Web applications, with which you have full control of both the client-side and server-side
code, APIs are meant to be used by clients beyond your control. For this reason, backward
compatibility (BC) of the APIs should be maintained whenever possible. If a change that may break BC is necessary, you should introduce it in new version of the API, and bump up the version number. Existing clients can continue to use the old, working version of the API; and new or upgraded clients can get the new functionality in the new API version.
Regarding how to implement API versioning, a common practice is to embed the version number in the API URLs.
For example, `http://example.com/v1/users` stands for `/users` API of version 1. Another method of API versioning
which gains momentum recently is to put version numbers in the HTTP request headers, typically through the `Accept` header,
like the following:
> Tip: Refer to [Semantic Versioning](http://semver.org/)
for more information on designing API version numbers.
One common way to implement API versioning is to embed the version number in the API URLs.
For example, `http://example.com/v1/users` stands for the `/users` endpoint of API version 1.
Another method of API versioning,
which has gained momentum recently, is to put the version number in the HTTP request headers. This is typically done through the `Accept` header:
```
// via a parameter
......@@ -19,16 +21,16 @@ Accept: application/json; version=v1
Accept: application/vnd.company.myapp-v1+json
```
Both methods have pros and cons, and there are a lot of debates about them. Below we describe a practical strategy
of API versioning that is kind of a mix of these two methods:
Both methods have their pros and cons, and there are a lot of debates about each approach. Below you'll see a practical strategy
for API versioning that is a mix of these two methods:
* Put each major version of API implementation in a separate module whose ID is the major version number (e.g. `v1`, `v2`).
Naturally, the API URLs will contain major version numbers.
* Within each major version (and thus within the corresponding module), use the `Accept` HTTP request header
to determine the minor version number and write conditional code to respond to the minor versions accordingly.
For each module serving a major version, it should include the resource classes and the controller classes
serving for that specific version. To better separate code responsibility, you may keep a common set of
For each module serving a major version, the module should include the resource and controller classes
serving that specific version. To better separate code responsibility, you may keep a common set of
base resource and controller classes, and subclass them in each individual version module. Within the subclasses,
implement the concrete code such as `Model::fields()`.
......@@ -86,11 +88,11 @@ return [
];
```
As a result, `http://example.com/v1/users` will return the list of users in version 1, while
As a result of the above code, `http://example.com/v1/users` will return the list of users in version 1, while
`http://example.com/v2/users` will return version 2 users.
Using modules, code for different major versions can be well isolated. And it is still possible
to reuse code across modules via common base classes and other shared classes.
Thanks to modules, the code for different major versions can be well isolated. But modules make it still possible
to reuse code across the modules via common base classes and other shared resources.
To deal with minor version numbers, you may take advantage of the content negotiation
feature provided by the [[yii\filters\ContentNegotiator|contentNegotiator]] behavior. The `contentNegotiator`
......@@ -101,7 +103,7 @@ For example, if a request is sent with the HTTP header `Accept: application/json
after content negotiation, [[yii\web\Response::acceptParams]] will contain the value `['version' => 'v1']`.
Based on the version information in `acceptParams`, you may write conditional code in places
such as actions, resource classes, serializers, etc.
such as actions, resource classes, serializers, etc. to provide the appropriate functionality.
Since minor versions require maintaining backward compatibility, hopefully there are not much
Since minor versions by definition require maintaining backward compatibility, hopefully there would not be many
version checks in your code. Otherwise, chances are that you may need to create a new major version.
Testing environment setup
======================
> Note: This section is under development.
Yii2 has officially maintained integration with [`Codeception`](https://github.com/Codeception/Codeception) testing
framework that allows you to create the following test types:
- [Unit testing](test-unit.md) - verifies that a single unit of code is working as expected;
- [Functional testing](test-functional.md) - verifies scenarios from a user's perspective via browser emulation;
- [Acceptance testing](test-acceptance.md) - verifies scenarios from a user's perspective in a browser.
Yii provides ready to use test sets for all three test types in both
[`yii2-basic`](https://github.com/yiisoft/yii2/tree/master/apps/basic) and
[`yii2-advanced`](https://github.com/yiisoft/yii2/tree/master/apps/advanced) application templates.
In order to run tests you need to install [Codeception](https://github.com/Codeception/Codeception). A good way to
install it is the following:
```
composer global require "codeception/codeception=2.0.*"
composer global require "codeception/specify=*"
composer global require "codeception/verify=*"
```
If you've never used Composer for global packages before, run `composer global status`. It should output:
```
Changed current directory to <directory>
```
Then add `<directory>/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command
line globally.
......@@ -305,13 +305,13 @@ yii fixture User UserProfile
yii fixture User --append
// load all fixtures
yii fixture/load *
yii fixture/load "*"
// same as above
yii fixture *
yii fixture "*"
// load all fixtures except ones
yii fixture * -DoNotLoadThisOne
yii fixture "*" -DoNotLoadThisOne
// load fixtures, but search them in different namespace. By default namespace is: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'
......@@ -335,10 +335,10 @@ yii fixture/unload User
yii fixture/unload User,UserProfile
// unload all fixtures
yii fixture/unload all
yii fixture/unload "*"
// unload all fixtures except ones
yii fixture/unload all -DoNotUnloadThisOne
yii fixture/unload "*" -DoNotUnloadThisOne
```
......
Testing
=======
> Note: This section is under development.
Testing is an important part of software development. Whether we are aware of it or not, we conduct testing continuously.
For example, when we write a class in PHP, we may debug it step by step or simply use echo or die statements to verify
that implementation works according to our initial plan. In case of web application we're entering some test data in forms
to ensure the page interacts with us as expected. The testing process could be automated so that each time when we need
to verify something, we just need to call up the code that do it for us. The code that verifies that result matches what
we've planned is called test and the process of its creation and further execution is known as automated testing, which
is the main topic of testing chapters.
TODO:
- https://github.com/yiisoft/yii2/blob/master/extensions/codeception/README.md
Developing with tests
------------------
Testing is an important part of software development. Whether we are aware of it or not, we conduct testing continuously.
For example, when we write a class in PHP, we may debug it step by step or simply use echo or die statements to verify
that implementation is correct. In case of web application we're entering some test data in forms to ensure the page
interacts with us as expected. The testing process could be automated so that each time when we need to test something,
we just need to call up the code that perform testing for us. This is known as automated testing, which is the main topic
of testing chapters.
Test-Driven Development (TDD) and Behavior-Driven Development (BDD) are approaches of developing
software by describing behavior of a piece of code or the whole feature as a set of scenarios or tests before
writing actual code and only then creating the implementation that allows these tests to pass verifying that intended
behavior is achieved.
The process of developing a feature is the following:
- Create a new test that describes a feature to be implemented.
- Run new test and make sure it fails. It is expected since there's no implementation yet.
- Write simple code to make the new test pass.
- Run all tests and make sure they all pass.
- Improve code and make sure tests are still OK.
After it's done the process is repeated again for another feature or improvement. If existing feature is to be changed,
tests should be changed as well.
> **Tip**: If you feel that you are loosing time doing a lot of small and simple iterations try covering more by your
> test scenario so you do more before executing tests again. If you're debugging too much try doing the opposite.
The reason to create tests before doing any implemenation is that it allows you to focus on what do we want to achieve
and fully dive into "how to do it" afterwards. Usually it leads to better abstractions and easier test maintenance when
it comes to feature adjustments in for of less coupled components.
So to sum up pros of such approach are the following:
- Keeps you focused on one thing at a time so both planning and implementation are getting better.
- Results in test-covering more features in greater detail i.e. if tests are OK most probably nothing's broken.
In the long term it usually gives you a good time-saving effect.
> **Tip**: If you want to know more about the principles for gathering software requirements and modeling the subject
> matter it's good to learn [Domain Driven Development (DDD)](https://en.wikipedia.org/wiki/Domain-driven_design).
When and how to test
------------------
The testing support provided by Yii includes:
While test first approach described above makes sense for long term and relatively complex projects it could be overkill
for simpler ones. There are some indicators of when it's appropriate:
- [Unit testing](test-unit.md) - verifies that a single unit of code is working as expected.
- [Functional testing](test-functional.md) - verifies scenarios from a user's perspective via browser emulation.
- [Acceptance testing](test-acceptance.md) - verifies scenarios from a user's perspective in a browser.
- Project is already large and complex.
- Project requirements are starting to get complex. Project grows constantly.
- Project is meant to be long term.
- The cost of the failure is too high.
Yii provides ready to use test sets for all three testing types in both basic and advanced application templates.
There's nothing wrong in creating tests covering behavior of existing implementation.
Test environment setup
----------------------
- Project is a legacy one to be gradually renewed.
- You've got a project to work on and it has no tests.
In order to run tests with Yii you need to install [Codeception](http://codeception.com/). A good way to install it is
the following:
In some cases any form of automated testing could be overkill:
```
composer global require "codeception/codeception=2.0.*"
composer global require "codeception/specify=*"
composer global require "codeception/verify=*"
```
- Project is simple and isn't getting any complex.
- It's one-time project that's going to be expired.
If you've never used Composer for global packages run `composer global status`. It should output:
Still if you have time it's good to automate testing in these cases as well.
```
Changed current directory to <directory>
```
Further reading
-------------
Then add `<directory>/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command
line globally.
- Test Driven Development: By Example / Kent Beck. ISBN: 0321146530.
......@@ -77,6 +77,9 @@ file via the `appconfig` option when executing the command:
yii <route> --appconfig=path/to/config.php ...
```
> **Note**: When using `*` in console don't forget to quote it as `"*"` in order to avoid executing it as a shell
> command.
Creating your own console commands
----------------------------------
......@@ -151,3 +154,8 @@ public function actionIndex()
return 0;
}
```
There are some predefined constants you can use:
- `Controller::EXIT_CODE_NORMAL` with value of `0`;
- `Controller::EXIT_CODE_ERROR` with value of `1`.
......@@ -31,7 +31,7 @@ class TestCase extends Test
* The application configuration array may contain an optional `class` element which specifies the class
* name of the application instance to be created. By default, a [[\yii\web\Application]] instance will be created.
*/
public $appConfig = '@codeception/config/unit.php';
public $appConfig = '@tests/codeception/config/unit.php';
/**
......
......@@ -102,8 +102,7 @@ class BlameableBehavior extends AttributeBehavior
protected function getValue($event)
{
if ($this->value === null) {
$user = Yii::$app->getUser();
$user = Yii::$app->get('user', false);
return $user && !$user->isGuest ? $user->id : null;
} else {
return call_user_func($this->value, $event);
......
......@@ -25,10 +25,10 @@ use yii\test\FixtureTrait;
* yii fixture User
*
* #load all fixtures
* yii fixture *
* yii fixture "*"
*
* #load all fixtures except User
* yii fixture * -User
* yii fixture "*" -User
*
* #append fixtures to already loaded
* yii fixture User --append
......@@ -92,10 +92,10 @@ class FixtureController extends Controller
* yii fixture/load --append User UserProfile
*
* # load all available fixtures found under 'tests\unit\fixtures'
* yii fixture/load *
* yii fixture/load "*"
*
* # load all fixtures except User and UserProfile
* yii fixture/load * -User -UserProfile
* yii fixture/load "*" -User -UserProfile
* ~~~
*
* @throws Exception if the specified fixture does not exist.
......@@ -164,10 +164,10 @@ class FixtureController extends Controller
* yii fixture/unload User UserProfile
*
* # unload all fixtures found under 'tests\unit\fixtures'
* yii fixture/unload *
* yii fixture/unload "*"
*
* # unload all fixtures except User and UserProfile
* yii fixture/unload * -User -UserProfile
* yii fixture/unload "*" -User -UserProfile
* ~~~
*
* @throws Exception if the specified fixture does not exist.
......
......@@ -40,7 +40,17 @@ class Migration extends Component implements MigrationInterface
{
/**
* @var Connection|string the DB connection object or the application component ID of the DB connection
* that this migration should work with.
* that this migration should work with. Note that when a Migration object is created by
* the `migrate` command, this property will be overwritten by the command. If you do not want to
* use the DB connection provided by the command, you may override the [[init()]] method like the following:
*
* ```php
* public function init()
* {
* $this->db = 'db2';
* parent::init();
* }
* ```
*/
public $db = 'db';
......
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