mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-03 22:32:40 +08:00
Merge branch 'master' of github.com:yiichina/yii2
This commit is contained in:
@ -16,7 +16,7 @@ Active Record
|
||||
|
||||
```php
|
||||
$customer = new Customer();
|
||||
$customer->name = '李狗蛋';
|
||||
$customer->name = 'Qiang';
|
||||
$customer->save(); // 一行新数据插入 customer 表
|
||||
```
|
||||
|
||||
@ -25,7 +25,7 @@ $customer->save(); // 一行新数据插入 customer 表
|
||||
|
||||
```php
|
||||
$db->createCommand('INSERT INTO customer (name) VALUES (:name)', [
|
||||
':name' => '李狗蛋',
|
||||
':name' => 'Qiang',
|
||||
])->execute();
|
||||
```
|
||||
|
||||
@ -87,7 +87,7 @@ $email = $customer->email;
|
||||
要改变列值,只要给关联属性赋新值并保存对象即可:
|
||||
|
||||
```php
|
||||
$customer->email = '哪吒@example.com';
|
||||
$customer->email = 'james@example.com';
|
||||
$customer->save();
|
||||
```
|
||||
|
||||
@ -429,7 +429,7 @@ class Customer extends \yii\db\ActiveRecord
|
||||
`hasMany()` 返回 [[yii\db\ActiveQuery]] 对象,该对象允许你通过
|
||||
[[yii\db\ActiveQuery]] 方法定制查询。
|
||||
|
||||
如上声明后,执行`$customer->bigOrders` 就返回
|
||||
如上声明后,执行 `$customer->bigOrders` 就返回
|
||||
总额大于100的订单。使用以下代码更改设定值:
|
||||
|
||||
```php
|
||||
|
||||
@ -300,7 +300,7 @@ class MyForm extends Model
|
||||
// 以匿名函数形式定义的行内验证器
|
||||
['token', function ($attribute, $params) {
|
||||
if (!ctype_alnum($this->$attribute)) {
|
||||
$this->addError($attribute, '令牌本身必须包含字母或数字。');
|
||||
$this->addError($attribute, 'token 本身必须包含字母或数字。');
|
||||
}
|
||||
}],
|
||||
];
|
||||
@ -308,8 +308,8 @@ class MyForm extends Model
|
||||
|
||||
public function validateCountry($attribute, $params)
|
||||
{
|
||||
if (!in_array($this->$attribute, ['兲朝', '墙外'])) {
|
||||
$this->addError($attribute, '国家必须为 "兲朝" 或 "墙外" 中的一个。');
|
||||
if (!in_array($this->$attribute, ['USA', 'Web'])) {
|
||||
$this->addError($attribute, 'The country must be either "USA" or "Web".');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -339,8 +339,8 @@ class CountryValidator extends Validator
|
||||
{
|
||||
public function validateAttribute($model, $attribute)
|
||||
{
|
||||
if (!in_array($model->$attribute, ['兲朝', '墙外'])) {
|
||||
$this->addError($attribute, '国家必须为 "兲朝" 或 "墙外" 中的一个。');
|
||||
if (!in_array($model->$attribute, ['USA', 'Web'])) {
|
||||
$this->addError($attribute, 'The country must be either "USA" or "Web".');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
215
docs/guide-zh-CN/security-authentication.md
Executable file
215
docs/guide-zh-CN/security-authentication.md
Executable file
@ -0,0 +1,215 @@
|
||||
认证
|
||||
==============
|
||||
|
||||
认证是鉴定用户身份的过程。它通常使用一个标识符
|
||||
(如用户名或电子邮件地址)和一个加密令牌(比如密码或者存取令牌)来
|
||||
鉴别用户身份。认证是登录功能的基础。
|
||||
|
||||
Yii提供了一个认证框架,它连接了不同的组件以支持登录。欲使用这个框架,
|
||||
你主要需要做以下工作:
|
||||
|
||||
* 设置用户组件 [[yii\web\User|user]] ;
|
||||
* 创建一个类实现 [[yii\web\IdentityInterface]] 接口。
|
||||
|
||||
|
||||
## 配置 [[yii\web\User]] <span id="configuring-user"></span>
|
||||
|
||||
用户组件 [[yii\web\User|user]] 用来管理用户的认证状态。这需要你
|
||||
指定一个含有实际认证逻辑的认证类 [[yii\web\User::identityClass|identity class]]。
|
||||
在以下web应用的配置项中,将用户用户组件 [[yii\web\User|user]] 的
|
||||
认证类 [[yii\web\User::identityClass|identity class]] 配置成
|
||||
模型类 `app\models\User`, 它的实现将在下一节中讲述。
|
||||
|
||||
```php
|
||||
return [
|
||||
'components' => [
|
||||
'user' => [
|
||||
'identityClass' => 'app\models\User',
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
|
||||
## 认证接口 [[yii\web\IdentityInterface]] 的实现 <span id="implementing-identity"></span>
|
||||
|
||||
认证类 [[yii\web\User::identityClass|identity class]] 必须实现包含以下方法的
|
||||
认证接口 [[yii\web\IdentityInterface]]:
|
||||
|
||||
* [[yii\web\IdentityInterface::findIdentity()|findIdentity()]]:根据指定的用户ID查找
|
||||
认证模型类的实例,当你需要使用session来维持登录状态的时候会用到这个方法。
|
||||
* [[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]]:根据指定的存取令牌查找
|
||||
认证模型类的实例,该方法用于
|
||||
通过单个加密令牌认证用户的时候(比如无状态的RESTful应用)。
|
||||
* [[yii\web\IdentityInterface::getId()|getId()]]:获取该认证实例表示的用户的ID。
|
||||
* [[yii\web\IdentityInterface::getAuthKey()|getAuthKey()]]:获取基于 cookie 登录时使用的认证密钥。
|
||||
认证密钥储存在 cookie 里并且将来会与服务端的版本进行比较以确保
|
||||
cookie的有效性。
|
||||
* [[yii\web\IdentityInterface::validateAuthKey()|validateAuthKey()]] :是基于 cookie 登录密钥的
|
||||
验证的逻辑的实现。
|
||||
|
||||
用不到的方法可以空着,例如,你的项目只是一个
|
||||
无状态的 RESTful 应用,只需实现 [[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]]
|
||||
和 [[yii\web\IdentityInterface::getId()|getId()]] ,其他的方法的函数体留空即可。
|
||||
|
||||
下面的例子是一个通过结合了 `user` 数据表的
|
||||
AR 模型 [Active Record](db-active-record.md) 实现的一个认证类 [[yii\web\User::identityClass|identity class]]。
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use yii\db\ActiveRecord;
|
||||
use yii\web\IdentityInterface;
|
||||
|
||||
class User extends ActiveRecord implements IdentityInterface
|
||||
{
|
||||
public static function tableName()
|
||||
{
|
||||
return 'user';
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给到的ID查询身份。
|
||||
*
|
||||
* @param string|integer $id 被查询的ID
|
||||
* @return IdentityInterface|null 通过ID匹配到的身份对象
|
||||
*/
|
||||
public static function findIdentity($id)
|
||||
{
|
||||
return static::findOne($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 token 查询身份。
|
||||
*
|
||||
* @param string $token 被查询的 token
|
||||
* @return IdentityInterface|null 通过 token 得到的身份对象
|
||||
*/
|
||||
public static function findIdentityByAccessToken($token, $type = null)
|
||||
{
|
||||
return static::findOne(['access_token' => $token]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|string 当前用户ID
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string 当前用户的(cookie)认证密钥
|
||||
*/
|
||||
public function getAuthKey()
|
||||
{
|
||||
return $this->auth_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $authKey
|
||||
* @return boolean if auth key is valid for current user
|
||||
*/
|
||||
public function validateAuthKey($authKey)
|
||||
{
|
||||
return $this->getAuthKey() === $authKey;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如上所述,如果你的应用利用 cookie 登录,
|
||||
你只需要实现 `getAuthKey()` 和 `validateAuthKey()` 方法。这样的话,你可以使用下面的代码在
|
||||
`user` 表中生成和存储每个用户的认证密钥。
|
||||
|
||||
```php
|
||||
class User extends ActiveRecord implements IdentityInterface
|
||||
{
|
||||
......
|
||||
|
||||
public function beforeSave($insert)
|
||||
{
|
||||
if (parent::beforeSave($insert)) {
|
||||
if ($this->isNewRecord) {
|
||||
$this->auth_key = \Yii::$app->security->generateRandomString();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 注意:不要混淆 `user` 认证类和用户组件 [[yii\web\User]]。前者是实现
|
||||
认证逻辑的类,通常用关联了
|
||||
持久性存储的用户信息的AR模型 [Active Record](db-active-record.md) 实现。后者是负责管理用户认证状态的
|
||||
应用组件。
|
||||
|
||||
|
||||
## 使用用户组件 [[yii\web\User]] <span id="using-user"></span>
|
||||
|
||||
在 `user` 应用组件方面,你主要用到 [[yii\web\User]] 。
|
||||
|
||||
你可以使用表达式 `Yii::$app->user->identity` 检测当前用户身份。它返回
|
||||
一个表示当前登录用户的认证类 [[yii\web\User::identityClass|identity class]] 的实例,
|
||||
未认证用户(游客)则返回 null。下面的代码展示了如何从 [[yii\web\User]]
|
||||
获取其他认证相关信息:
|
||||
|
||||
```php
|
||||
// 当前用户的身份实例。未认证用户则为 Null 。
|
||||
$identity = Yii::$app->user->identity;
|
||||
|
||||
// 当前用户的ID。 未认证用户则为 Null 。
|
||||
$id = Yii::$app->user->id;
|
||||
|
||||
// 判断当前用户是否是游客(未认证的)
|
||||
$isGuest = Yii::$app->user->isGuest;
|
||||
```
|
||||
|
||||
你可以使用下面的代码登录用户:
|
||||
|
||||
```php
|
||||
// 使用指定用户名获取用户身份实例。
|
||||
// 请注意,如果需要的话您可能要检验密码
|
||||
$identity = User::findOne(['username' => $username]);
|
||||
|
||||
// 登录用户
|
||||
Yii::$app->user->login($identity);
|
||||
```
|
||||
|
||||
[[yii\web\User::login()]] 方法将当前用户的身份登记到 [[yii\web\User]]。如果 session 设置为
|
||||
[[yii\web\User::enableSession|enabled]],则使用 session 记录用户身份,用户的
|
||||
认证状态将在整个会话中得以维持。如果开启自动登录 [[yii\web\User::enableAutoLogin|enabled]]
|
||||
则基于 cookie 登录(如:记住登录状态),它将使用 cookie 保存用户身份,这样
|
||||
只要 cookie 有效就可以恢复登录状态。
|
||||
|
||||
为了使用 cookie 登录,你需要在应用配置文件中将 [[yii\web\User::enableAutoLogin]]
|
||||
设为 true。你还需要在 [[yii\web\User::login()]] 方法中
|
||||
传递有效期(记住登录状态的时长)参数。
|
||||
|
||||
注销用户:
|
||||
|
||||
```php
|
||||
Yii::$app->user->logout();
|
||||
```
|
||||
|
||||
请注意,启用 session 时注销用户才有意义。该方法将从内存和 session 中
|
||||
同时清理用户认证状态。默认情况下,它还会注销所有的
|
||||
用户会话数据。如果你希望保留这些会话数据,可以换成 `Yii::$app->user->logout(false)` 。
|
||||
|
||||
|
||||
## 认证事件 <span id="auth-events"></span>
|
||||
|
||||
[[yii\web\User]] 类在登录和注销流程引发一些事件。
|
||||
|
||||
* [[yii\web\User::EVENT_BEFORE_LOGIN|EVENT_BEFORE_LOGIN]]:在登录 [[yii\web\User::login()]] 时引发。
|
||||
如果事件句柄将事件对象的 [[yii\web\UserEvent::isValid|isValid]] 属性设为 false,
|
||||
登录流程将会被取消。
|
||||
* [[yii\web\User::EVENT_AFTER_LOGIN|EVENT_AFTER_LOGIN]]:登录成功后引发。
|
||||
* [[yii\web\User::EVENT_BEFORE_LOGOUT|EVENT_BEFORE_LOGOUT]]:注销 [[yii\web\User::logout()]] 前引发。
|
||||
如果事件句柄将事件对象的 [[yii\web\UserEvent::isValid|isValid]] 属性设为 false,
|
||||
注销流程将会被取消。
|
||||
* [[yii\web\User::EVENT_AFTER_LOGOUT|EVENT_AFTER_LOGOUT]]:成功注销后引发。
|
||||
|
||||
你可以通过响应这些事件来实现一些类似登录统计、在线人数统计的功能。例如,
|
||||
在登录后 [[yii\web\User::EVENT_AFTER_LOGIN|EVENT_AFTER_LOGIN]] 的处理程序,你可以将用户的登录时间和IP记录到
|
||||
`user` 表中。
|
||||
@ -1,24 +1,24 @@
|
||||
Fixtures(夹具)
|
||||
========
|
||||
|
||||
Fixtures是测试的重要组成部分。 他们的主要目的是在一个固定/已知的环境的状态安装环境以确保测试可重复并且按照预期方式运行。 Yii提供了fixture框架,通过fixture框架我们能够精确定义我们的fixtures并且很简单的使用他们。
|
||||
Fixtures 是测试的重要组成部分。 他们的主要目的是在一个固定/已知的环境的状态安装环境以确保测试可重复并且按照预期方式运行。Yii提供了 fixture 框架,通过 fixture 框架我们能够精确定义我们的 fixtures 并且很简单的使用他们。
|
||||
|
||||
Yii的Fixture框架中一个关键的概念就是所谓的 *fixture对象*。 Fixture对象代表测试环境的一个特殊方面,是 [[yii\test\Fixture]]或其子类的一个实例 。 例如,
|
||||
Yii 的 Fixture 框架中一个关键的概念就是所谓的 *fixture对象*。 Fixture 对象代表测试环境的一个特殊方面,是 [[yii\test\Fixture]] 或其子类的一个实例 。 例如,
|
||||
你可以使用`UserFixture`确保user数据库表包含一个固定的数据集合.在你运行一个测试之前加载一个或者多个Fixture对象,并且在完成测试的时候卸载他们。
|
||||
|
||||
一个Fixture可能依赖其他Fixtures,我们可以通过指定他的[[yii\test\Fixture::depends]] 属性设置依赖关系。
|
||||
当一个Fixture被加载的时候,其依赖的Fixtures将在它加载之前被自动加载;
|
||||
并且这个Fixture将被卸载的时候,其依赖的Fixtures将在它卸载之后卸载。
|
||||
一个 Fixture 可能依赖其他 Fixtures,我们可以通过指定他的 [[yii\test\Fixture::depends]] 属性设置依赖关系。
|
||||
当一个 Fixture 被加载的时候,其依赖的 Fixtures 将在它加载之前被自动加载;
|
||||
并且这个 Fixture 将被卸载的时候,其依赖的 Fixtures 将在它卸载之后卸载。
|
||||
|
||||
|
||||
定义一个 Fixture
|
||||
------------------
|
||||
|
||||
通过创建一个继承与[[yii\test\Fixture]]或[[yii\test\ActiveFixture]]的类来定义一个Fixture。
|
||||
牵着特别适合一般用途的Fixtures, 而后者则具有扩展功能,特别是配合数据库(DB)和活跃记录(AR)工作。
|
||||
通过创建一个继承与 [[yii\test\Fixture]] 或 [[yii\test\ActiveFixture]] 的类来定义一个 Fixture。
|
||||
牵着特别适合一般用途的 Fixtures, 而后者则具有扩展功能,特别是配合数据库(DB)和活跃记录(AR)工作。
|
||||
|
||||
|
||||
下面代码定义了一个关于`User`活跃记录和相应user表的Fixture。
|
||||
下面代码定义了一个关于 `User` 活跃记录和相应 user 表的 Fixture。
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -32,19 +32,19 @@ class UserFixture extends ActiveFixture
|
||||
}
|
||||
```
|
||||
|
||||
> 技巧:为了测试的目的每个`ActiveFixture`都准备一张数据库表.我们可以通过设定[[yii\test\ActiveFixture::tableName]]或者[[yii\test\ActiveFixture::modelClass]]属性指定表。 如果是后者,表的名字将从通过`modelClass`指定`ActiveRecord`类获得。
|
||||
> 技巧:为了测试的目的每个 `ActiveFixture` 都准备一张数据库表.我们可以通过设定[[yii\test\ActiveFixture::tableName]]或者[[yii\test\ActiveFixture::modelClass]]属性指定表。 如果是后者,表的名字将从通过 `modelClass` 指定 `ActiveRecord` 类获得。
|
||||
|
||||
> 注意: [[yii\test\ActiveFixture]]只适用于SQL数据库.对于NoSQL数据库, Yii提供了以下
|
||||
> `ActiveFixture`类:
|
||||
> 注意: [[yii\test\ActiveFixture]] 只适用于 SQL 数据库.对于 NoSQL 数据库,Yii 提供了以下
|
||||
> `ActiveFixture` 类:
|
||||
>
|
||||
> - Mongo DB: [[yii\mongodb\ActiveFixture]]
|
||||
> - Elasticsearch: [[yii\elasticsearch\ActiveFixture]] (since version 2.0.2)
|
||||
|
||||
|
||||
`ActiveFixture` Fixture的Fixture数据通常被位于`FixturePath/data/TableName.php`的文件提供,
|
||||
`FixturePath`代表包含Fixture类文件的目录,`TableName`
|
||||
是与Fixture相关联的表名称.上面例子当中, 文件格式应该是
|
||||
`@app/tests/fixtures/data/user.php`。 这个数据文件应该返回一个将要插入user表数据行的数组。例如,
|
||||
`ActiveFixture` Fixture 的 Fixture 数据通常被位于 `FixturePath/data/TableName.php` 的文件提供,
|
||||
`FixturePath` 代表包含Fixture类文件的目录,`TableName`
|
||||
是与 Fixture 相关联的表名称.上面例子当中, 文件格式应该是
|
||||
`@app/tests/fixtures/data/user.php`。 这个数据文件应该返回一个将要插入 user 表数据行的数组。例如,
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -65,16 +65,16 @@ return [
|
||||
```
|
||||
|
||||
在后期的测试当中,你可以给行指定一个别名,你可以通过别名来引用这些行.在上面例子当中,
|
||||
两行的别名分别是`user1`和`user2`。
|
||||
两行的别名分别是 `user1` 和 `user2`。
|
||||
|
||||
同时, 你不必指定自增列数据。当Fixture被加载成功的时候Yii将自动填充这些实际值到这些行。
|
||||
同时, 你不必指定自增列数据。当 Fixture 被加载成功的时候 Yii 将自动填充这些实际值到这些行。
|
||||
|
||||
> 技巧:你可以通过设定[[yii\test\ActiveFixture::dataFile]]属性定制数据文件位置。
|
||||
> 你也可以通过重写[[yii\test\ActiveFixture::getData()]]方法来提供数据.
|
||||
> 技巧:你可以通过设定 [[yii\test\ActiveFixture::dataFile]] 属性定制数据文件位置。
|
||||
> 你也可以通过重写 [[yii\test\ActiveFixture::getData()]] 方法来提供数据.
|
||||
|
||||
前面我们提到,一个Fixture可能依赖Fixtures。例如,`UserProfileFixture`可能依赖`UserFixture`
|
||||
因为user profile表包含一个指向user表的外键。
|
||||
依赖可以通过[[yii\test\Fixture::depends]]属性指定,格式如下,
|
||||
前面我们提到,一个 Fixture 可能依赖 Fixtures。例如,`UserProfileFixture` 可能依赖 `UserFixture`
|
||||
因为 user profile 表包含一个指向user表的外键。
|
||||
依赖可以通过 [[yii\test\Fixture::depends]] 属性指定,格式如下,
|
||||
|
||||
```php
|
||||
namespace app\tests\fixtures;
|
||||
@ -88,23 +88,23 @@ class UserProfileFixture extends ActiveFixture
|
||||
}
|
||||
```
|
||||
|
||||
依赖关系确保了这些Fixtures的加载和卸载按照预先定义的顺序进行。 在上面的例子,`UserFixture`将在`UserProfileFixture`加载之前被加载,以确保所有的外键引用存在,并且在`UserProfileFixture`卸载之后被同样原因卸载。
|
||||
依赖关系确保了这些 Fixtures 的加载和卸载按照预先定义的顺序进行。 在上面的例子,`UserFixture` 将在 `UserProfileFixture` 加载之前被加载,以确保所有的外键引用存在,并且在 `UserProfileFixture` 卸载之后被同样原因卸载。
|
||||
|
||||
在上面例子当中,我们已经展示了如何定义一个和数据库表相关的Fixture。定义一个和数据库无关的Fixture
|
||||
(例如。 一个和已经确定的文件和目录相关的Fixture), 你可以继承[[yii\test\Fixture]]这些普通的基类,并且重写 [[yii\test\Fixture::load()|load()]]和[[yii\test\Fixture::unload()|unload()]] 方法。
|
||||
在上面例子当中,我们已经展示了如何定义一个和数据库表相关的 Fixture。定义一个和数据库无关的 Fixture
|
||||
(例如。 一个和已经确定的文件和目录相关的 Fixture), 你可以继承 [[yii\test\Fixture]] 这些普通的基类,并且重写 [[yii\test\Fixture::load()|load()]] 和 [[yii\test\Fixture::unload()|unload()]] 方法。
|
||||
|
||||
|
||||
使用 Fixtures
|
||||
--------------
|
||||
|
||||
如果你使用[CodeCeption](http://codeception.com/)测试你的代码,你可以考虑使用这些为加载和访问Fixtures提供内建支持的`yii2-codeception`扩展。
|
||||
如果你使用[CodeCeption](http://codeception.com/)测试你的代码,你可以考虑使用这些为加载和访问 Fixtures 提供内建支持的 `yii2-codeception` 扩展。
|
||||
|
||||
如果你想使用其他测试框架,你可以在你的测试用例当中使用[[yii\test\FixtureTrait]]达到同样的目的。
|
||||
如果你想使用其他测试框架,你可以在你的测试用例当中使用 [[yii\test\FixtureTrait]] 达到同样的目的。
|
||||
|
||||
下面我们将描述如何用`yii2-codeception`编写一个`UserProfile`单元测试类。
|
||||
下面我们将描述如何用 `yii2-codeception` 编写一个 `UserProfile` 单元测试类。
|
||||
|
||||
单元测试类继承 [[yii\codeception\DbTestCase]] 或[[yii\codeception\TestCase]],
|
||||
在[[yii\test\FixtureTrait::fixtures()|fixtures()]] 方法中声明你想使用的Fixtures。 例如,
|
||||
单元测试类继承 [[yii\codeception\DbTestCase]] 或 [[yii\codeception\TestCase]],
|
||||
在 [[yii\test\FixtureTrait::fixtures()|fixtures()]] 方法中声明你想使用的 Fixtures。 例如,
|
||||
|
||||
```php
|
||||
namespace app\tests\unit\models;
|
||||
@ -125,16 +125,16 @@ class UserProfileTest extends DbTestCase
|
||||
}
|
||||
```
|
||||
|
||||
`fixtures()`方法列出的Fixtures在每一个测试用例的测试方法运行之前被自动加载,在每一个测试方法完成的 时候被卸载. 并且我们前面提到,当一个Fixture被加载的时候,所有他所依赖的Fixtures将首先被自动加载.在上面例子当中,因为
|
||||
`UserProfileFixture`依赖`UserFixture`,当运行这个测试类中的任何一个测试方法,
|
||||
`fixtures()` 方法列出的 Fixtures 在每一个测试用例的测试方法运行之前被自动加载,在每一个测试方法完成的 时候被卸载. 并且我们前面提到,当一个 Fixture 被加载的时候,所有他所依赖的 Fixtures 将首先被自动加载.在上面例子当中,因为
|
||||
`UserProfileFixture` 依赖 `UserFixture`,当运行这个测试类中的任何一个测试方法,
|
||||
两个Fixtures被自动加载: `UserFixture` 和 `UserProfileFixture`。
|
||||
|
||||
当在`fixtures()`方法中指定Fixtures的时候, 你可以使用一个类名称或者一个指向Fixture的数组引用配置. 当Fixture被加载的时候,此配置数组可以让你定制Fixture属性。
|
||||
当在 `fixtures()` 方法中指定Fixtures的时候, 你可以使用一个类名称或者一个指向 Fixture 的数组引用配置. 当 Fixture 被加载的时候,此配置数组可以让你定制 Fixture 属性。
|
||||
|
||||
你也可以分配一个别名给Fixture。 在上面例子当中, `UserProfileFixture`的别名为 `profiles`。
|
||||
在测试方法中, 你可能用他的别名来访问一个Fixture对象。例如, `$this->profiles`将返回`UserProfileFixture`对象。
|
||||
你也可以分配一个别名给 Fixture 。 在上面例子当中, `UserProfileFixture`的别名为 `profiles`。
|
||||
在测试方法中, 你可能用他的别名来访问一个 Fixture 对象。例如, `$this->profiles`将返回 `UserProfileFixture` 对象。
|
||||
|
||||
因为`UserProfileFixture` 继承 `ActiveFixture`, 你可以进一步使用下面语法来访问通过这个Fixture提供的数据:
|
||||
因为 `UserProfileFixture` 继承 `ActiveFixture`, 你可以进一步使用下面语法来访问通过这个 Fixture 提供的数据:
|
||||
|
||||
```php
|
||||
// 返回数据行别名 'user1'
|
||||
@ -152,22 +152,22 @@ foreach ($this->profiles as $row) ...
|
||||
定义并使用全局 Fixtures
|
||||
----------------------------------
|
||||
|
||||
以上描述的ixtures主要用于个别测试用例。在大多数情况下,你需要一些适用于所有或者许多测试用例的全局Fixtures。[[yii\test\InitDbFixture]]做两件事情的例子:
|
||||
以上描述的 ixtures 主要用于个别测试用例。在大多数情况下,你需要一些适用于所有或者许多测试用例的全局 Fixtures。[[yii\test\InitDbFixture]] 做两件事情的例子:
|
||||
|
||||
*通过执行位于`@app/tests/fixtures/initdb.php`的脚本,执行某些常见的初始化任务;
|
||||
* 加载其他数据库Fixtures之前禁用该数据库完整性检查,并且在其他数据库Fixtures被卸载的时候重新启用该数据库。
|
||||
*通过执行位于 `@app/tests/fixtures/initdb.php` 的脚本,执行某些常见的初始化任务;
|
||||
* 加载其他数据库 Fixtures 之前禁用该数据库完整性检查,并且在其他数据库 Fixtures 被卸载的时候重新启用该数据库。
|
||||
|
||||
像使用非全局Fixtures那样使用全局Fixtures。唯一的不同就是你在[[yii\codeception\TestCase::globalFixtures()]]声明那些Fixtures而不是在`fixtures()`中。当一个测试用例加载Fixtures的时候,它将首先加载全局Fixtures然后再加载非全局的Fixtures。
|
||||
像使用非全局Fixtures那样使用全局 Fixtures 。唯一的不同就是你在 [[yii\codeception\TestCase::globalFixtures()]] 声明那些 Fixtures 而不是在 `fixtures()` 中。当一个测试用例加载 Fixtures 的时候,它将首先加载全局Fixtures然后再加载非全局的 Fixtures。
|
||||
|
||||
默认情况下, [[yii\codeception\DbTestCase]] 在他的`globalFixtures()`方法中已经声明了`InitDbFixture`。
|
||||
这意味着,如果在测试之前你想做一些初始化的工作,你只需要围绕着`@app/tests/fixtures/initdb.php`编码。 否则,你可能只专注于开发每个单独的测试案例和相应的Fixtures.
|
||||
默认情况下, [[yii\codeception\DbTestCase]] 在他的 `globalFixtures()` 方法中已经声明了 `InitDbFixture`。
|
||||
这意味着,如果在测试之前你想做一些初始化的工作,你只需要围绕着 `@app/tests/fixtures/initdb.php` 编码。 否则,你可能只专注于开发每个单独的测试案例和相应的 Fixtures.
|
||||
|
||||
|
||||
组织 Fixture 类和数据文件
|
||||
-----------------------------------------
|
||||
|
||||
默认情况下, Fixture类去一个包含Fixture类文件`data`目录的子目录中寻找相应数据文件。在简单的项目工作时,你可以遵循这个约定。
|
||||
对于大项目, 机会是,您经常为同一个Fixture类的不同测试需要切换不同的数据文件。因为我们推荐你以类似于类命名空间的层次方式组织你的数据文件。 例如,
|
||||
默认情况下, Fixture 类去一个包含 Fixture 类文件 `data` 目录的子目录中寻找相应数据文件。在简单的项目工作时,你可以遵循这个约定。
|
||||
对于大项目, 机会是,您经常为同一个 Fixture 类的不同测试需要切换不同的数据文件。因为我们推荐你以类似于类命名空间的层次方式组织你的数据文件。 例如,
|
||||
|
||||
```
|
||||
# tests\unit\fixtures 目录结构
|
||||
@ -186,14 +186,14 @@ data\
|
||||
# 等等
|
||||
```
|
||||
|
||||
用这种方式你可以避免测试和使用需求之间的Fixture数据文件冲突。
|
||||
用这种方式你可以避免测试和使用需求之间的 Fixture 数据文件冲突。
|
||||
|
||||
> 注意: 上面的例子,Fixture文件的命名只是为了举例。 在实际开发中,你应该根据该Fixture类继
|
||||
> 承的基类命名。例如,如果你的数据库Fixtures继承[[yii\test\ActiveFixture]],
|
||||
> 你应该用数据库表名作为Fixture文件名;
|
||||
> 如果你的MongoDB Fixtures继承[[yii\mongodb\ActiveFixture]] , 你应该用集合名作为Fixture文件名。
|
||||
|
||||
以蕾丝与层次结构的方式组织Fixtures类文件。 不用 `data`作根目录,用`fixtures`目录作为根目录来避免数据文件冲突。
|
||||
以蕾丝与层次结构的方式组织 Fixtures 类文件。 不用 `data` 作根目录,用 `fixtures` 目录作为根目录来避免数据文件冲突。
|
||||
|
||||
|
||||
总结
|
||||
@ -201,13 +201,13 @@ data\
|
||||
|
||||
> 注意: 此部分在开发环境下进行。
|
||||
|
||||
前面,我们已经描述了如何去定义和使用Fixtures。 接下来,我们总结了一套典型的单元测试与数据库结合的工作流程:
|
||||
前面,我们已经描述了如何去定义和使用 Fixtures。 接下来,我们总结了一套典型的单元测试与数据库结合的工作流程:
|
||||
|
||||
1. 使用 `yii migrate`工具升级你的测试数据库到最新的版本;
|
||||
1. 使用 `yii migrate` 工具升级你的测试数据库到最新的版本;
|
||||
2. 运行测试用例:
|
||||
- 加载Fixtures:清理相关数据库表并且用Fixture数据填充他们;
|
||||
- 加载 Fixtures:清理相关数据库表并且用 Fixture 数据填充他们;
|
||||
- 执行实际测试;
|
||||
- 卸载Fixtures。
|
||||
- 卸载 Fixtures。
|
||||
3. 重复步骤2,直到所有的测试执行完毕。
|
||||
|
||||
|
||||
@ -220,19 +220,19 @@ data\
|
||||
>
|
||||
> 待办事项: 此教程可以和test-fixtures.md的上述部分合并。
|
||||
|
||||
Fixtures是测试的重要组成部分。他的主要目的是需要通过测试不同的用例数据来填充。把这些数据用到你的测试当中,测试会变得更加高效和有意义。
|
||||
Fixtures 是测试的重要组成部分。他的主要目的是需要通过测试不同的用例数据来填充。把这些数据用到你的测试当中,测试会变得更加高效和有意义。
|
||||
|
||||
Yii 通过`yii fixture`这个命令行工具为Fixtures提供支持,这个工具支持:
|
||||
Yii 通过 `yii fixture` 这个命令行工具为 Fixtures 提供支持,这个工具支持:
|
||||
|
||||
* 加载Fixtures到不同的存储设备,例如: RDBMS, NoSQL, etc;
|
||||
* 以不同的方式卸载Fixtures (通常他会清除存储设备);
|
||||
* 自动生成Fixtures并且用随机数据去填充他它。
|
||||
* 加载 Fixtures 到不同的存储设备,例如: RDBMS, NoSQL, etc;
|
||||
* 以不同的方式卸载 Fixtures (通常他会清除存储设备);
|
||||
* 自动生成 Fixtures 并且用随机数据去填充他它。
|
||||
|
||||
Fixtures 格式
|
||||
---------------
|
||||
|
||||
Fixtures是不同方法和配置的对象, 官方引用[documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md) 。
|
||||
让我们假设有Fixtures数据加载:
|
||||
Fixtures 是不同方法和配置的对象, 官方引用 [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md) 。
|
||||
让我们假设有 Fixtures数据加载:
|
||||
|
||||
```
|
||||
#Fixtures 数据目录的 users.php 文件,默认 @tests\unit\fixtures\data
|
||||
@ -254,22 +254,22 @@ return [
|
||||
],
|
||||
];
|
||||
```
|
||||
如果我们使用Fixture将数据加载到数据库,那么这些行将被应用于 `users` 表。 如果我们使用nosql Fixtures,例如 `mongodb`
|
||||
fixture,那么这些数据将应用于`users` mongodb 集合。 为了了解更多实现各种加载策略,访问官网 [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md)。
|
||||
上面的Fixture案例是由`yii2-faker`扩展自动生成的, 在这里了解更多 [section](#auto-generating-fixtures).
|
||||
如果我们使用 Fixture 将数据加载到数据库,那么这些行将被应用于 `users` 表。 如果我们使用 nosql Fixtures,例如 `mongodb`
|
||||
fixture,那么这些数据将应用于 `users` mongodb 集合。 为了了解更多实现各种加载策略,访问官网 [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md)。
|
||||
上面的Fixture案例是由 `yii2-faker` 扩展自动生成的, 在这里了解更多 [section](#auto-generating-fixtures).
|
||||
Fixture类名不应该是复数形式。
|
||||
|
||||
加载 Fixtures
|
||||
----------------
|
||||
|
||||
Fixture类应该以`Fixture`类作为后缀。默认的Fixtures能在`tests\unit\fixtures` 命名空间下被搜索到,你可以通过配置和命名行选项来更改这个行为,你能因为加载或者卸载指定它名字前面的`-`来排除一些Fixtures,像`-User`.
|
||||
Fixture 类应该以 `Fixture` 类作为后缀。默认的Fixtures能在 `tests\unit\fixtures` 命名空间下被搜索到,你可以通过配置和命名行选项来更改这个行为,你能因为加载或者卸载指定它名字前面的`-`来排除一些 Fixtures,像 `-User`.
|
||||
|
||||
运行如下命令去加载Fixture:
|
||||
运行如下命令去加载 Fixture:
|
||||
|
||||
```
|
||||
yii fixture/load <fixture_name>
|
||||
```
|
||||
必需参数`fixture_name`指定一个将被加载数据的Fixture名字。 你可以同时加载多个Fixtures。
|
||||
必需参数 `fixture_name` 指定一个将被加载数据的 Fixture 名字。 你可以同时加载多个 Fixtures。
|
||||
以下是这个命令的正确格式:
|
||||
|
||||
```
|
||||
@ -342,6 +342,6 @@ yii fixture/unload "*" -DoNotUnloadThisOne
|
||||
自动生成 fixtures
|
||||
------------------------
|
||||
|
||||
Yii 还可以为你自动生成一些基于一些模板的Fixtures。 你能够以不同语言格式用不同的数据生成你的Fixtures.
|
||||
Yii 还可以为你自动生成一些基于一些模板的 Fixtures。 你能够以不同语言格式用不同的数据生成你的 Fixtures.
|
||||
这些特征由 [Faker](https://github.com/fzaninotto/Faker) 库和 `yii2-faker` 扩展完成。
|
||||
关注 [guide](https://github.com/yiisoft/yii2-faker) 扩展获取更多的文档。
|
||||
|
||||
Reference in New Issue
Block a user