原文地址:
https://docs.acquia.com/articles/drupal-8-functional-tests
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
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
追加一个功能测试
要创建功能测试,在 tests/src/Functional/ 内创建一个以 Test.php 结尾的文件。象大多数 Drupal 8 特征那样,我们通过创建一个继承 BrowserTestBase 的类创建测试。我们也使用 Drupal\Tests\[module_name]\Functional 作为所有测试类的名字空间。
这个模式和单元测试很象,只是把路径和名字空间中的 Unit 替换为 Functional 。
src/Tests/TestExampleUserTest.php
<?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 的功能测试需要有两个注解,@runTestsInSeparateProcesses 和 @preserveGlobalState disabled 。 - 激活的模块
因为功能测试运行在没有完全构建的 Drupal 系统内,所以我们需要列出所有依赖。我们列出模块,这样测试才知道要激活它。 - setUp
我们的测试里,有必要调用 parent::setUp,因为这些功能测试的 setup 相当复杂。我们也能调用特定的 drupalCreateUser() 方法,它允许我们访问用户实体。 - 测试方法
和单元测试一样,方法以 test 开头。 - 断言语句
断言语句和 PHPUnit 单元测试相同。这个例子里,我们检查是否用户实体存在一个字段。用户实体有一个我们可以使用的 getFieldDefinitions() 方法。这对于单元测试有效,但它默认返回 null。我们在测试这个字段是否存在,所有我们不想模拟这个函数,我们想知道实际上它是否返回我们的字段。
运行这个功能测试
要运行功能测试 ,我们需要告诉 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 就包含了本课我们使用的模式。