diff --git a/apps/advanced/tests/codeception/backend/_bootstrap.php b/apps/advanced/tests/codeception/backend/_bootstrap.php index affe4081d8..69c38520d6 100644 --- a/apps/advanced/tests/codeception/backend/_bootstrap.php +++ b/apps/advanced/tests/codeception/backend/_bootstrap.php @@ -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__))); diff --git a/apps/advanced/tests/codeception/backend/acceptance.suite.yml b/apps/advanced/tests/codeception/backend/acceptance.suite.yml index 0157530a2e..f93f392e24 100644 --- a/apps/advanced/tests/codeception/backend/acceptance.suite.yml +++ b/apps/advanced/tests/codeception/backend/acceptance.suite.yml @@ -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, diff --git a/apps/advanced/tests/codeception/backend/acceptance/LoginCept.php b/apps/advanced/tests/codeception/backend/acceptance/LoginCept.php index e86b3f3713..bb6c65f80c 100644 --- a/apps/advanced/tests/codeception/backend/acceptance/LoginCept.php +++ b/apps/advanced/tests/codeception/backend/acceptance/LoginCept.php @@ -1,7 +1,7 @@ wantTo('ensure login page works'); diff --git a/apps/advanced/tests/codeception/backend/codeception.yml b/apps/advanced/tests/codeception/backend/codeception.yml index 088fd21653..c16ac4765b 100644 --- a/apps/advanced/tests/codeception/backend/codeception.yml +++ b/apps/advanced/tests/codeception/backend/codeception.yml @@ -1,4 +1,4 @@ -namespace: codeception_backend +namespace: tests\codeception\backend actor: Tester paths: tests: . diff --git a/apps/advanced/tests/codeception/backend/functional.suite.yml b/apps/advanced/tests/codeception/backend/functional.suite.yml index 8945473581..5bf5c8b7f5 100644 --- a/apps/advanced/tests/codeception/backend/functional.suite.yml +++ b/apps/advanced/tests/codeception/backend/functional.suite.yml @@ -11,7 +11,7 @@ modules: enabled: - Filesystem - Yii2 - - codeception\common\_support\FixtureHelper + - tests\codeception\common\_support\FixtureHelper config: Yii2: configFile: '../config/backend/functional.php' diff --git a/apps/advanced/tests/codeception/backend/functional/LoginCept.php b/apps/advanced/tests/codeception/backend/functional/LoginCept.php index 4322258d88..3072d97521 100644 --- a/apps/advanced/tests/codeception/backend/functional/LoginCept.php +++ b/apps/advanced/tests/codeception/backend/functional/LoginCept.php @@ -1,7 +1,7 @@ wantTo('ensure login page works'); diff --git a/apps/advanced/tests/codeception/backend/unit/DbTestCase.php b/apps/advanced/tests/codeception/backend/unit/DbTestCase.php index 4f5a5fd352..35baef91be 100644 --- a/apps/advanced/tests/codeception/backend/unit/DbTestCase.php +++ b/apps/advanced/tests/codeception/backend/unit/DbTestCase.php @@ -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'; } diff --git a/apps/advanced/tests/codeception/backend/unit/TestCase.php b/apps/advanced/tests/codeception/backend/unit/TestCase.php index 5fd4fbc632..ad734d93ba 100644 --- a/apps/advanced/tests/codeception/backend/unit/TestCase.php +++ b/apps/advanced/tests/codeception/backend/unit/TestCase.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'; } diff --git a/apps/advanced/tests/codeception/common/_bootstrap.php b/apps/advanced/tests/codeception/common/_bootstrap.php index b2d88d1e40..3e768208cc 100644 --- a/apps/advanced/tests/codeception/common/_bootstrap.php +++ b/apps/advanced/tests/codeception/common/_bootstrap.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 diff --git a/apps/advanced/tests/codeception/common/_pages/LoginPage.php b/apps/advanced/tests/codeception/common/_pages/LoginPage.php index 7f93ed0633..6a1dc84337 100644 --- a/apps/advanced/tests/codeception/common/_pages/LoginPage.php +++ b/apps/advanced/tests/codeception/common/_pages/LoginPage.php @@ -1,6 +1,6 @@ [ 'class' => UserFixture::className(), - 'dataFile' => '@codeception/common/fixtures/data/init_login.php', + 'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php', ], ]; } diff --git a/apps/advanced/tests/codeception/common/codeception.yml b/apps/advanced/tests/codeception/common/codeception.yml index 935e97c261..e8a3407a48 100644 --- a/apps/advanced/tests/codeception/common/codeception.yml +++ b/apps/advanced/tests/codeception/common/codeception.yml @@ -1,4 +1,4 @@ -namespace: codeception_common +namespace: tests\codeception\common actor: Tester paths: tests: . diff --git a/apps/advanced/tests/codeception/common/fixtures/UserFixture.php b/apps/advanced/tests/codeception/common/fixtures/UserFixture.php index db5e0d19a5..7153c8c0b3 100644 --- a/apps/advanced/tests/codeception/common/fixtures/UserFixture.php +++ b/apps/advanced/tests/codeception/common/fixtures/UserFixture.php @@ -1,6 +1,6 @@ [ 'class' => UserFixture::className(), - 'dataFile' => '@codeception/common/unit/fixtures/data/models/user.php' + 'dataFile' => '@tests/codeception/common/unit/fixtures/data/models/user.php' ], ]; } diff --git a/apps/advanced/tests/codeception/config/backend/acceptance.php b/apps/advanced/tests/codeception/config/backend/acceptance.php index bf9204c8f7..ce673f8ca2 100644 --- a/apps/advanced/tests/codeception/config/backend/acceptance.php +++ b/apps/advanced/tests/codeception/config/backend/acceptance.php @@ -1,5 +1,9 @@ wantTo('ensure that about works'); diff --git a/apps/advanced/tests/codeception/frontend/acceptance/ContactCept.php b/apps/advanced/tests/codeception/frontend/acceptance/ContactCept.php index c80469ee9c..c537fd4807 100644 --- a/apps/advanced/tests/codeception/frontend/acceptance/ContactCept.php +++ b/apps/advanced/tests/codeception/frontend/acceptance/ContactCept.php @@ -1,6 +1,6 @@ wantTo('ensure that contact works'); diff --git a/apps/advanced/tests/codeception/frontend/acceptance/HomeCept.php b/apps/advanced/tests/codeception/frontend/acceptance/HomeCept.php index efbcddbb86..5cf837916f 100644 --- a/apps/advanced/tests/codeception/frontend/acceptance/HomeCept.php +++ b/apps/advanced/tests/codeception/frontend/acceptance/HomeCept.php @@ -1,5 +1,5 @@ wantTo('ensure that home page works'); diff --git a/apps/advanced/tests/codeception/frontend/acceptance/LoginCept.php b/apps/advanced/tests/codeception/frontend/acceptance/LoginCept.php index cc8411d8de..e4363a837d 100644 --- a/apps/advanced/tests/codeception/frontend/acceptance/LoginCept.php +++ b/apps/advanced/tests/codeception/frontend/acceptance/LoginCept.php @@ -1,6 +1,6 @@ wantTo('ensure login page works'); diff --git a/apps/advanced/tests/codeception/frontend/acceptance/SignupCest.php b/apps/advanced/tests/codeception/frontend/acceptance/SignupCest.php index 9b86b953ab..ab4b7bba28 100644 --- a/apps/advanced/tests/codeception/frontend/acceptance/SignupCest.php +++ b/apps/advanced/tests/codeception/frontend/acceptance/SignupCest.php @@ -1,8 +1,8 @@ wantTo('ensure that about works'); diff --git a/apps/advanced/tests/codeception/frontend/functional/ContactCept.php b/apps/advanced/tests/codeception/frontend/functional/ContactCept.php index 9630b0de83..1aaac3f5a1 100644 --- a/apps/advanced/tests/codeception/frontend/functional/ContactCept.php +++ b/apps/advanced/tests/codeception/frontend/functional/ContactCept.php @@ -1,6 +1,6 @@ wantTo('ensure that contact works'); diff --git a/apps/advanced/tests/codeception/frontend/functional/HomeCept.php b/apps/advanced/tests/codeception/frontend/functional/HomeCept.php index c250e43402..0f5b2ffbb9 100644 --- a/apps/advanced/tests/codeception/frontend/functional/HomeCept.php +++ b/apps/advanced/tests/codeception/frontend/functional/HomeCept.php @@ -1,5 +1,5 @@ wantTo('ensure that home page works'); $I->amOnPage(Yii::$app->homeUrl); diff --git a/apps/advanced/tests/codeception/frontend/functional/LoginCept.php b/apps/advanced/tests/codeception/frontend/functional/LoginCept.php index c5d94afa59..0fb3477614 100644 --- a/apps/advanced/tests/codeception/frontend/functional/LoginCept.php +++ b/apps/advanced/tests/codeception/frontend/functional/LoginCept.php @@ -1,6 +1,6 @@ wantTo('ensure login page works'); diff --git a/apps/advanced/tests/codeception/frontend/functional/SignupCest.php b/apps/advanced/tests/codeception/frontend/functional/SignupCest.php index 0ed81b7a22..525b0373fa 100644 --- a/apps/advanced/tests/codeception/frontend/functional/SignupCest.php +++ b/apps/advanced/tests/codeception/frontend/functional/SignupCest.php @@ -1,8 +1,8 @@ [ 'class' => UserFixture::className(), - 'dataFile' => '@codeception/frontend/unit/fixtures/data/models/user.php' + 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php' ], ]; } diff --git a/apps/advanced/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php b/apps/advanced/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php index 1997b2f4f7..a2f5012400 100644 --- a/apps/advanced/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php +++ b/apps/advanced/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php @@ -1,9 +1,9 @@ [ 'class' => UserFixture::className(), - 'dataFile' => '@codeception/frontend/unit/fixtures/data/models/user.php' + 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php' ], ]; } diff --git a/apps/advanced/tests/codeception/frontend/unit/models/SignupFormTest.php b/apps/advanced/tests/codeception/frontend/unit/models/SignupFormTest.php index ff8b56d288..4d869f1122 100644 --- a/apps/advanced/tests/codeception/frontend/unit/models/SignupFormTest.php +++ b/apps/advanced/tests/codeception/frontend/unit/models/SignupFormTest.php @@ -1,9 +1,9 @@ [ 'class' => UserFixture::className(), - 'dataFile' => '@codeception/frontend/unit/fixtures/data/models/user.php', + 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php', ], ]; } diff --git a/apps/basic/tests/README.md b/apps/basic/tests/README.md index 1c4b50bcac..34439f8a27 100644 --- a/apps/basic/tests/README.md +++ b/apps/basic/tests/README.md @@ -21,20 +21,40 @@ Changed current directory to Then add `/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 diff --git a/apps/basic/tests/codeception/_bootstrap.php b/apps/basic/tests/codeception/_bootstrap.php index 5f5ae10b42..9855939782 100644 --- a/apps/basic/tests/codeception/_bootstrap.php +++ b/apps/basic/tests/codeception/_bootstrap.php @@ -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__)); diff --git a/apps/basic/tests/codeception/_pages/AboutPage.php b/apps/basic/tests/codeception/_pages/AboutPage.php index b6ca34a293..b56320d093 100644 --- a/apps/basic/tests/codeception/_pages/AboutPage.php +++ b/apps/basic/tests/codeception/_pages/AboutPage.php @@ -1,6 +1,6 @@ wantTo('ensure that about works'); diff --git a/apps/basic/tests/codeception/acceptance/ContactCept.php b/apps/basic/tests/codeception/acceptance/ContactCept.php index c9adc7e15e..98ba2ef12c 100644 --- a/apps/basic/tests/codeception/acceptance/ContactCept.php +++ b/apps/basic/tests/codeception/acceptance/ContactCept.php @@ -1,6 +1,6 @@ wantTo('ensure that contact works'); diff --git a/apps/basic/tests/codeception/acceptance/LoginCept.php b/apps/basic/tests/codeception/acceptance/LoginCept.php index 6d07c08958..4f022e1c28 100644 --- a/apps/basic/tests/codeception/acceptance/LoginCept.php +++ b/apps/basic/tests/codeception/acceptance/LoginCept.php @@ -1,6 +1,6 @@ wantTo('ensure that login works'); diff --git a/apps/basic/tests/codeception/bin/yii_acceptance b/apps/basic/tests/codeception/bin/yii_acceptance index f67a47fbbb..99ac417472 100644 --- a/apps/basic/tests/codeception/bin/yii_acceptance +++ b/apps/basic/tests/codeception/bin/yii_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_acceptance', diff --git a/apps/basic/tests/codeception/bin/yii_functional b/apps/basic/tests/codeception/bin/yii_functional index f6e3988a06..39efa983b2 100644 --- a/apps/basic/tests/codeception/bin/yii_functional +++ b/apps/basic/tests/codeception/bin/yii_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_functional', diff --git a/apps/basic/tests/codeception/bin/yii_unit b/apps/basic/tests/codeception/bin/yii_unit index 1ab8e1fbae..f99ec5333f 100644 --- a/apps/basic/tests/codeception/bin/yii_unit +++ b/apps/basic/tests/codeception/bin/yii_unit @@ -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', diff --git a/apps/basic/tests/codeception/fixtures/.gitignore b/apps/basic/tests/codeception/fixtures/.gitignore new file mode 100644 index 0000000000..c96a04f008 --- /dev/null +++ b/apps/basic/tests/codeception/fixtures/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/apps/basic/tests/codeception/functional/AboutCept.php b/apps/basic/tests/codeception/functional/AboutCept.php index 3edd61da31..ae7b45b308 100644 --- a/apps/basic/tests/codeception/functional/AboutCept.php +++ b/apps/basic/tests/codeception/functional/AboutCept.php @@ -1,6 +1,6 @@ wantTo('ensure that about works'); diff --git a/apps/basic/tests/codeception/functional/ContactCept.php b/apps/basic/tests/codeception/functional/ContactCept.php index c5e83b4f19..47604058d7 100644 --- a/apps/basic/tests/codeception/functional/ContactCept.php +++ b/apps/basic/tests/codeception/functional/ContactCept.php @@ -1,6 +1,6 @@ wantTo('ensure that contact works'); diff --git a/apps/basic/tests/codeception/functional/LoginCept.php b/apps/basic/tests/codeception/functional/LoginCept.php index 4cb283ac97..991d27c3c9 100644 --- a/apps/basic/tests/codeception/functional/LoginCept.php +++ b/apps/basic/tests/codeception/functional/LoginCept.php @@ -1,6 +1,6 @@ wantTo('ensure that login works'); diff --git a/apps/basic/tests/codeception/templates/.gitignore b/apps/basic/tests/codeception/templates/.gitignore new file mode 100644 index 0000000000..c96a04f008 --- /dev/null +++ b/apps/basic/tests/codeception/templates/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/apps/basic/tests/codeception/unit/models/ContactFormTest.php b/apps/basic/tests/codeception/unit/models/ContactFormTest.php index 8adda18c61..3234829432 100644 --- a/apps/basic/tests/codeception/unit/models/ContactFormTest.php +++ b/apps/basic/tests/codeception/unit/models/ContactFormTest.php @@ -1,6 +1,6 @@ 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 +... +``` diff --git a/docs/guide/rest-versioning.md b/docs/guide/rest-versioning.md index 0b876ca742..50b4e1ae00 100644 --- a/docs/guide/rest-versioning.md +++ b/docs/guide/rest-versioning.md @@ -1,16 +1,18 @@ 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. diff --git a/docs/guide/test-environment-setup.md b/docs/guide/test-environment-setup.md new file mode 100644 index 0000000000..28ecc33f8d --- /dev/null +++ b/docs/guide/test-environment-setup.md @@ -0,0 +1,33 @@ +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 +``` + +Then add `/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command +line globally. diff --git a/docs/guide/test-fixtures.md b/docs/guide/test-fixtures.md index ddd243565e..4ee2962142 100644 --- a/docs/guide/test-fixtures.md +++ b/docs/guide/test-fixtures.md @@ -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 ``` diff --git a/docs/guide/test-overview.md b/docs/guide/test-overview.md index 3d20db3818..0243ccec48 100644 --- a/docs/guide/test-overview.md +++ b/docs/guide/test-overview.md @@ -1,44 +1,75 @@ Testing ======= -> Note: This section is under development. - -TODO: - -- https://github.com/yiisoft/yii2/blob/master/extensions/codeception/README.md - 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. +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. -The testing support provided by Yii includes: -- [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. +Developing with tests +------------------ -Yii provides ready to use test sets for all three testing types in both basic and advanced application templates. +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. -Test environment setup ----------------------- +The process of developing a feature is the following: -In order to run tests with Yii you need to install [Codeception](http://codeception.com/). A good way to install it 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. -``` -composer global require "codeception/codeception=2.0.*" -composer global require "codeception/specify=*" -composer global require "codeception/verify=*" -``` +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. -If you've never used Composer for global packages run `composer global status`. It should output: +> **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. -``` -Changed current directory to -``` +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. -Then add `/vendor/bin` to you `PATH` environment variable. Now we're able to use `codecept` from command -line globally. +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 +------------------ + +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: + +- 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. + +There's nothing wrong in creating tests covering behavior of existing implementation. + +- Project is a legacy one to be gradually renewed. +- You've got a project to work on and it has no tests. + +In some cases any form of automated testing could be overkill: + +- Project is simple and isn't getting any complex. +- It's one-time project that's going to be expired. + +Still if you have time it's good to automate testing in these cases as well. + +Further reading +------------- + +- Test Driven Development: By Example / Kent Beck. ISBN: 0321146530. diff --git a/docs/guide/tutorial-console.md b/docs/guide/tutorial-console.md index af49f56b28..6f2132b7b9 100644 --- a/docs/guide/tutorial-console.md +++ b/docs/guide/tutorial-console.md @@ -77,6 +77,9 @@ file via the `appconfig` option when executing the command: yii --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`. diff --git a/extensions/codeception/TestCase.php b/extensions/codeception/TestCase.php index 1d331d82a4..a810cb6e51 100644 --- a/extensions/codeception/TestCase.php +++ b/extensions/codeception/TestCase.php @@ -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'; /** diff --git a/framework/behaviors/BlameableBehavior.php b/framework/behaviors/BlameableBehavior.php index 791a07748a..b1ff94f08a 100644 --- a/framework/behaviors/BlameableBehavior.php +++ b/framework/behaviors/BlameableBehavior.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); diff --git a/framework/console/controllers/FixtureController.php b/framework/console/controllers/FixtureController.php index 37b0bf4c44..181f00ded8 100644 --- a/framework/console/controllers/FixtureController.php +++ b/framework/console/controllers/FixtureController.php @@ -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. diff --git a/framework/db/Migration.php b/framework/db/Migration.php index 6326636470..25fff24042 100644 --- a/framework/db/Migration.php +++ b/framework/db/Migration.php @@ -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';