10.3 功能测试
Drupal 8 中的功能测试需要你有一个正在运行的站点,并且安装了 SimpleTest(核心内) 模块。该测试中我们会向用户(user)实体追加一个字段,之后检查用户是否存在这个字段。我们需要使用功能测试,因为我们需要引导 Drupal 获得用户对象。当然通过单体测试检查这个也可以,但我们最终处理的是很复杂的一个系统。
PHPUnit 和 SimpleTest 功能测试(BrowserTestBase / WebTestBase)
标准和未来的默认功能测试系统是使用 PHPUnit 和基类 BrowserTestBase 。很多核心使用老的功能测试系统 SimpleTest 以及 WebTestBase 。基于 PHPUnit 的测试能从 IDE 运行。SimpleTest 测试运行稍复杂一些,我们将在后边覆盖到。
当前 BrowserTestBase
的主要限制是不能使用 JavaScript 和 AJAX 。如果你的测试需要它们,那么在 JavaScript 被添加到 BrowserTestBase 之前还得使用老的 WebTestBase
。
追加用户字段
第一个测试,我们向用户实体追加一个字段,之后测试这个字段是否有效。
test_example.info.yml (见辅助内容区)
name: Test Example
type: module
description: Example showing how to create tests
core: 8.x
package: Examples
dependencies:
- user
- options
config/install/field.field.user.user.test_status.yml
使用这个文件定义字段:(见辅助内容区)
langcode: en
status: true
dependencies:
config:
- field.storage.user.test_status
id: user.user.test_status
field_name: test_status
entity_type: user
bundle: user
label: test_status
description: ''
required: false
translatable: false
default_value:
-
value: 0
default_value_callback: ''
settings:
on_label: 'On'
off_label: 'Off'
field_type: boolean
config/install/field.storage.user.test_status.yml (见辅助内容区)
追加一个功能测试
要创建功能测试,在 tests/src/Functional/ 内创建一个以 Test.php 结尾的文件。象大多数 Drupal 8 特征那样,我们通过创建一个继承 BrowserTestBase 的类创建测试。我们也使用 Drupal\Tests\[module_name]\Functional 作为所有测试类的名字空间。
这个模式和单体测试很象,只是把路径和名字空间中的 Unit 替换为 Functional
。
langcode: en
status: true
dependencies:
module:
- user
id: user.test_status
field_name: test_status
entity_type: user
type: boolean
settings: { }
module: test_example
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
src/Tests/TestExampleUserTest.php (见辅助内容区)
- 注解
所有使用 PhpUnit 的功能测试需要有两个注解,@runTestsInSeparateProcesses
和@preserveGlobalState
disabled 。 - 激活的模块
因为功能测试运行在没有完全构建的 Drupal 系统内,所以我们需要列出所有依赖。我们列出模块,这样测试才知道要激活它。 - setUp
我们的测试里,有必要调用 parent::setUp,因为这些功能测试的 setup 相当复杂。我们也能调用特定的drupalCreateUser()
方法,它允许我们访问用户实体。 - 测试方法
和单体测试一样,方法以 test 开头。 - 断言语句
断言语句和 PHPUnit 单体测试相同。这个例子里,我们检查是否用户实体存在一个字段。用户实体有一个我们可以使用的 getFieldDefinitions() 方法。这对于单体测试有效,但它默认返回 null。我们在测试这个字段是否存在,所有我们不想模拟这个函数,我们想知道实际上它是否返回我们的字段。
<?php
/**
* @file
*
* Contains \Drupal\Tests\test_example\Functional\TestExampleUserTest.
*/
namespace Drupal\Tests\test_example\Functional;
use Drupal\simpletest\BrowserTestBase;
/**
* Check if our user field works.
*
* @group test_example
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
*/
class TestExampleUserTest extends BrowserTestBase {
/**
* @var \Drupal\user\Entity\User.
*/
protected $user;
/**
* Enabled modules
*/
public static $modules = ['test_example'];
/**
* {@inheritdoc}
*/
function setUp() {
parent::setUp();
$this->user = $this->drupalCreateUser();
}
/**
* Test that the user has a test_status field.
*/
public function testUserHasTestStatusField() {
$this->assertTrue(in_array('test_status', array_keys($this->user->getFieldDefinitions())));
}
}
运行这个功能测试
要运行功能测试 ,我们需要告诉 PHPUnit 去哪里访问我们的站点。在 PhpStorm 中通过设置一个环境变量实现这个。
- 打开 PhpStorm
- 在 Command Line 部分,编辑 Environment 变量。
- 用名 SIMPLETEST_BASE_URL 和值(站点URL)添加一个新条目。
你能使用 Run 按钮,象运行单体测试那样运行这个测试。
AJAX 遗留功能测试(SimpleTest)
和 PHPUnit 功能测试一样,如果你使用 AJAX ,在 JavaScript 追加到 BrowserTestBase 之前只能使用 SimpleTest 系统。你需要有一个安装了 SimpleTest 模块的站点。
PHPUnit 功能测试和 SimpleTest 功能测试的区别
两种测试类型有相似之处,但当你需要使用两者时,差异足够产生困惑。
文件命名和名字空间
要创建 SimpleTest 功能测试,你必须在 src/Tests/ 内创建一个以 Test.php 结尾的文件。象大多数 Drupal 8 特征那样,我们通过继承基类 WebTestBase 或 KernelTestBase 创建测试。我们也使用 Drupal\[module_name]\Tests 作为所有测试类的名字空间。这个模式很象 PHPUnit 测试,但不准确。PHPUnit 功能测试位于 tests/src/Functional 内,而 SimpleTest 测试在 src/Tests 内 。同样,名字空间和基类也不相同。
测试文件例子 src/Tests/TestExampleUserTest.php :(见辅助内容区)
<?php
/**
* @file
*
* Contains \Drupal\test_example\Tests\TestExampleUserTest.
*/
namespace Drupal\test_example\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Check if our user field works.
*
* @group test_example
*/
class TestExampleUserTest extends WebTestBase {
/**
* @var \Drupal\user\Entity\User.
*/
protected $user;
/**
* Enabled modules
*/
public static $modules = ['test_example'];
/**
* {@inheritdoc}
*/
function setUp() {
parent::setUp();
$this->user = $this->drupalCreateUser();
}
/**
* Test that the user has a test_status field.
*/
public function testUserHasTestStatusField() {
$this->assertTrue(in_array('test_status', array_keys($this->user->getFieldDefinitions())));
}
}
额外的功能测试目标
Drupal 核心里有很多功能测试。
core/modules/user/src/Tests/UserBlocksTest.php 包含了本课我们使用的模式,也检查输出形式。