Drupal 8 模块开发 10.3 : 功能测试

Drupal8模块开发

原文地址:
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 中通过设置一个环境变量实现这个。

  1. 打开 PhpStorm
  2. Command Line 部分,编辑 Environment 变量。
  3. 用名 SIMPLETEST_BASE_URL 和值(站点URL)添加一个新条目。
    Configure PHP Unit

你能使用 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 就包含了本课我们使用的模式。    

添加新评论