Drupal → FAQ по тестированию

19.11.2025

Пополняемый список коротких ответов на вопросы по тестированию.

KernelTestBase

Как при создании теста определить список нужных модулей в $modules?

Только методом тыка — пишем тест, запускаем, читаем ошибку, добавляем нужный модуль в $modules, повторяем пока ошибки не пропадут.
Как в тесте получить сервис?

class ExampleTest extends KernelTestBase {

  public function test(): void {
    // По FQCN (если у сервиса есть соответствующий alias)
    $entity_type_manager = $this->container->get(\Drupal\Core\Entity\EntityTypeManagerInterface::class);
    
    // Или по имени сервиса
    $entity_type_manager = $this->container->get('entity_type.manager');
  }
  
}
Как создать пользователя?

Создание обычного пользователя с определёнными правами:

class ExampleTest extends KernelTestBase {
  use UserCreationTrait;

  protected static $modules = [
    'user',
  ];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('user');
  }

  public function test(): void {
    $admin_user = $this->createUser(
      permissions: ['create page content', 'delete page content'], // Optional
      name: 'John Smith', // Optional
      values: ['mail' => 'john.smith@test.local'], // Optional
    );
  }
}

Создание админа со всеми правами:

class ExampleTest extends KernelTestBase {
  use UserCreationTrait;

  protected static $modules = [
    'user',
    'system', // Обязательно
  ];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('user');
  }

  public function test(): void {
    $admin_user = $this->createUser(admin: TRUE);
  }
}
Как залогиниться под главным администратором?

class ExampleTest extends KernelTestBase {

  use UserCreationTrait;
  
  protected static $modules = [
    'user',
    'system',
  ];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('user');
  }
  
  public function test(): void {
    $this->setUpCurrentUser(admin: TRUE);
    ...
  }

}
Как залогиниться под определённым пользователем?

С помощью \Drupal\Tests\user\Traits\UserCreationTrait::setUpCurrentUser() или \Drupal\Tests\user\Traits\UserCreationTrait::setCurrentUser():

class ExampleTest extends KernelTestBase {

  use UserCreationTrait;
  
  protected static $modules = [
    'user',
  ];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('user');
  }
  
  public function test(): void {
    $this->setUpCurrentUser(
      values: ['name' => 'John Smith'], // Optional
      permissions: ['create page content', 'delete page content'], // Optional
      admin: FALSE, // Optional
    );
    
    // Или так, если пользователь уже есть
    $this->setCurrentUser($user);
  }

}
Как создать ноду? Как создать сущность?

class ExampleTest extends KernelTestBase {

  use ContentTypeCreationTrait;

  protected static $modules = [
    'node',
  ];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('node');
    $this->createContentType(['type' => 'page']);
  }
  
  public function test(): void {
    // Стандартные вариант - через хелпер \Drupal\Core\Entity\EntityInterface::create()
    $node = Node::create(['type' => 'page', 'title' => 'Test node']);
    $node->save();
    
    // Более правильный вариант - через \Drupal\Core\Entity\EntityStorageInterface
    $node_storage = $this->container->get(EntityTypeManagerInterface::class)->getStorage('node');
    $node = $node_storage->create(['type' => 'page', 'title' => 'Test node']);
    $node_storage->save($node);
  }

}

Для многих сущностей есть тестовые фабрики, например для нод это \Drupal\Tests\node\Traits\NodeCreationTrait::createNode():

class ExampleTest extends KernelTestBase {

  use ContentTypeCreationTrait;
  use NodeCreationTrait;

  protected static $modules = [
    'node',
  ];

  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('node');
    $this->createContentType(['type' => 'page']);
  }
  
  public function test(): void {
    $node = $this->createNode(values: ['type' => 'page']);
  }

}

Список некоторых фабрик из ядра:
- \Drupal\Tests\block\Traits\BlockCreationTrait::placeBlock()
- \Drupal\Tests\node\Traits\ContentTypeCreationTrait::createContentType()
- \Drupal\Tests\node\Traits\NodeCreationTrait::createNode()
- \Drupal\Tests\user\Traits\UserCreationTrait::createUser()
- \Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait::createVocabulary()
- \Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait::createTerm()

Как изменить конфиг?

С помощью $this->config($config_name)->set($param_name, $param_value)->save():

class ExampleTest extends KernelTestBase {

  public function setUp(): void {
    parent::setUp();
    $this->config('system.date')->set('timezone.default', 'UTC')->save();
  }

}
Как задать настройки в settings.php?

Через $this->setSetting($setting_name, $value):

class ExampleTest extends KernelTestBase {

  public function test(): void {
    $this->setSetting('file_public_path', 'files');
    ...
  }

}
Как создать в БД таблицу, описанную в hook_schema()?

С помощью $this->installSchema($module_name, $table_names):

class ExampleTest extends KernelTestBase {

  public function setUp(): void {
    parent::setUp();
    $this->installSchema('MODULENAME', ['TABLE_NAME']);
  }

}
Как установить конфиги из определённого модуля?

С помощью $this->installConfig($module_name):

class ExampleTest extends KernelTestBase {

  protected static $modules = [
    'system',
  ];

  public function setUp(): void {
    parent::setUp();
    $this->installConfig('system');
  }

}
Как получить рендер-массив сущности?

class ExampleTest extends KernelTestBase {

  public function test(): void {
    $entity_type_manager = $this->container->get(EntityTypeManagerInterface::class);
    $view_builder = $entity_type_manager->getViewBuilder('ENTITY_TYPE_ID');
    $entity = $entity_type_manager->getStorage('ENTITY_TYPE_ID')->load(123);
    $build = $view_builder->view($entity);
    $build = $view_builder->build($build);
    ...
  }

}
Как отрендерить рендер-массив?

class ExampleTest extends KernelTestBase {

  public function test(): void {
    $build = [
      '#prefix' => '<p>',
      '#markup' => 'Hello, World!',
      '#suffix' => '</p>',
    ];
    $renderer = $this->container->get(\Drupal\Core\Render\RendererInterface::class);
    $html = (string)$renderer->renderRoot($build); // "<p>Hello, World</p>!"
    ...
  }

}
Как замокать определённый сервис? Как переопределить определённый сервис?

С помощью $this->prophesize() или создания анонимного класса:

class ExampleTest extends KernelTestBase {

  public function test(): void {
    $path_matcher = $this->prophesize(PathMatcherInterface::class);
    $path_matcher->isFrontPage()->willReturn(TRUE);
    $this->container->set('path.matcher', $path_matcher->reveal());
    ...
    
    // Или так
    $path_matcher = new class() implements PathMatcherInterface {
      public function matchPath($path, $patterns) {
        return FALSE;
      }
      public function isFrontPage() {
        return TRUE;
      }
    }
    $this->container->set('path.matcher', $path_matcher);
    ...
  }

}
Как выполнить drush команду?

class ExampleTest extends KernelTestBase {

  use \Drush\TestTraits\DrushTestTrait;

  public function test(): void {
    $this->drush(
      command: 'my:command',
      args: ['param1-value', 'param2-value'],
      options: ['option1-name' => 'value1', 'option2-name' => 'value2'],
    );
    $this->assertOutputEquals('...');
  }

}

Подробнее

Как протестировать drush команду?

Пример тестирование команды AgeCommand:

final class AgeCommandTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'MODULENAME',
  ];

  /**
   * {@selfdoc}
   */
  public function test(): void {
    $command = new AgeCommand($this->container->get(TimeInterface::class));
    $tester = new CommandTester($command);
    $tester->execute(['birth_date' => date('Y-m-d', strtotime('-18 years'))]);
    self::assertSame(Command::SUCCESS, $tester->getStatusCode());
    self::assertSame('18', rtrim($tester->getDisplay()));
  }

}
Как выполнить hook_install определённого модуля?

final class ExampleTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'MODULENAME',
  ];

  /**
   * {@inheritDoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->container->get(ModuleHandlerInterface::class)->invoke('MODULENAME', 'install');
  }

}

BrowserTestBase

Метод $this->drupalGet() посылает реальные http запросы или эмулирует их?

$this->drupalGet() посылает реальные http запросы с помощью Guzzle и curl. Запросы посылаются на домен, указанный в переменной окружения SIMPLETEST_BASE_URL.
Как создать пользователя?

С помощью хелпера $this->createUser() или его синонима $this->drupalCreateUser():

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    // Создание обычного пользователя
    $user = $this->createUser(
      permissions: ['create page content', 'delete page content'], // Optional
      name: 'Test user', // Optional
      admin: FALSE, // Optional
      values: ['mail' => 'test@test.test'], // Optional
    );
    
    // Создание админа со всеми правами
    $admin = $this->createUser(admin: TRUE);
  }

}
Как создать роль и пользователя с этой ролью?

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->createRole(permissions: ['create page content'], rid: 'manager', name: 'Content manager');
    $user = $this->createUser(values: ['roles' => 'manager']);
    ...
  }

}
Как войти под главным администратором (uid=1)?

В BrowserTestBase тестах главный админ создаётся автоматически и доступен в $this->rootUser:

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalLogin($this->rootUser);
    ...
  }

}
Как войти под определённым пользователем?

С помощью $this->drupalLogin($user):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $user = $this->createUser();
    $this->drupalLogin($user);
    ...
  }

}
Как разлогинить пользователя?

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    // Способ 1 - эмулирует выход используя браузер
    $this->drupalLogout();

    // Способ 2 - устанавливает текущим пользователем анонима
    $this->drupalResetSession();
  }

}
Как изменить конфиг?

С помощью $this->config($config_name)->set($param_name, $value)->save():

class ExampleTest extends BrowserTestBase {

  public function setUp(): void {
    parent::setUp();
    $this->config('system.date')->set('timezone.default', 'UTC')->save();
  }

}
Как изменить настройки в settings.php?

С помощью $this->writeSettings():

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $settings['settings']['hash_salt'] = (object) [
      'value' => Crypt::randomBytesBase64(55),
      'required' => TRUE,
    ];
    $this->writeSettings($settings);
  }

}

Код пропишет в settings.php строку $settings['hash_salt'] = '...'; и пересоздаст сервис \Drupal\Core\Site\Settings

Как разместить на страницах блок с заголовком страницы? Как разместить блок?

С помощью $this->placeBlock($plugin_id, $settings):

class ExampleTest extends BrowserTestBase {

  public function setUp(): void {
    parent::setUp();
    $this->drupalPlaceBlock('page_title_block');
  }

}
Как отправить форму?

С помощью $this->submitForm($form_data, $button):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->submitForm([
      'Username' => 'admin',
      'Password' => 'qwerty',
    ], 'Log in');
    ...
  }

}

В ключах массива можно передавать либо лейблы полей, либо их атрибут name.

Как отправить форму с чекбоксом?

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/path/to/form');
    $this->submitForm([
      'First checkbox' => 1, // Checked
      'Second checkbox' => 0, // Unchecked
    ], 'Submit');
    ...
  }

}
Как проверить наличие текста на странице?

С помощью $this->assertSession()->pageTextContains($text):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->assertSession()->pageTextContains('Log in');
  }

}
Как проверить наличие текста в определённом html элементе?

С помощью $this->assertSession()->elementTextContains($selectorType, $selector, $text):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->assertSession()->elementTextContains('css', 'h1', 'Log in');
  }

}
Как проверить текст в системном сообщении?

С помощью $this->assertSession()->statusMessageContains($text):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->submitForm([
      'Username' => 'admin',
      'Password' => 'qwerty',
    ], 'Log in');
    $this->assertSession()->statusMessageContains('Unrecognized username or password');
  }

}
Как проверить наличие html элемента на странице?

С помощью $this->assertSession()->elementExists($selector_type, $selector):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->assertSession()->elementExists('css', '.tabs--primary');
  }

}
Как проверить наличие input элемента на странице?

С помощью $this->assertSession()->fieldExists($field):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->assertSession()->fieldExists('Username');
  }

}

В fieldExists() можно указывать лейбл поля, html id, либо html name.

Как проверить значение в input элементе?

С помощью $this->assertSession()->fieldValueEquals($field, $value):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->assertSession()->fieldValueEquals('Username', '');
  }

}
Как проверить значение атрибута у html элемента?

С помощью $this->assertSession()->elementAttributeContains():

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->assertSession()->elementAttributeContains(
      selectorType: 'css',
      selector: 'input[name="name"]',
      attribute: 'autocomplete',
      text: 'username',
    );
  }

}
Как проверить текущий url?

С помощью $this->assertSession()->addressEquals($path) или $this->assertSession()->addressMatches($regexp):

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $this->submitForm([
      'Username' => 'admin',
      'Password' => 'qwerty',
    ], 'Log in');
    $this->assertSession()->addressEquals('/user/1');
    // Или
    $this->assertSession()->addressMatches('#^/user/\d+$#');
  }

}
Как получить текущий url?

С помощью $this->getSession()->getCurrentUrl():

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->drupalGet('/user/login');
    $current_url = $this->getSession()->getCurrentUrl(); // "https://example.com/user/login"
    ...
  }

}
Как добавить язык?

С помощью \Drupal\Tests\language\Traits\LanguageTestTrait::createLanguageFromLangcode():

class ExampleTest extends BrowserTestBase {

  use \Drupal\Tests\language\Traits\LanguageTestTrait;

  public function test(): void {
    $language = $this::createLanguageFromLangcode('ru');
    ...
  }

}
Как добавить перевод строки?

class ExampleTest extends BrowserTestBase {

  public function test(): void {
    $this->addTranslation('Home', 'Главная');
    ...
  }

  private function addTranslation(string $en_string, string $ru_string, string $context = ''): void {
    $locale_storage = $this->container->get(\Drupal\locale\StringStorageInterface::class);

    $string_object = $locale_storage->createString([
      'source' => $en_string,
      'context' => $context,
    ])->save();
    $locale_storage->createTranslation([
      'lid' => $string_object->lid,
      'language' => 'ru',
      'translation' => $ru_string,
    ])->save();
  }

}
Как добавить сущности поле?

Пример создания числового поля для сущности entity_test:

class ExampleTest extends BrowserTestBase {

  protected static $modules = [
    'entity_test',
    'user',
    'field',
  ];

  public function test(): void {
    $entity_type_manager = $this->container->get(EntityTypeManagerInterface::class);

    // Create field storage.
    $field_storage = $entity_type_manager->getStorage('field_storage_config')->create([
      'field_name' => 'my_integer_field',
      'type' => 'integer',
      'entity_type' => 'entity_test',
    ]);
    $field_storage->save();

    // Create field instance.
    $field_instance = $entity_type_manager->getStorage('field_config')->create([
      'field_storage' => $field_storage,
      'label' => 'My integer field',
      'bundle' => 'entity_test',
    ]);
    $field_instance->save();
  }

}

Отдельного хэлпера для создания поля нет :( Можно использовать свой:

  /**
   * Create field.
   */
  public function createField(
    string $field_name,
    string $field_type,
    string $entity_type = 'entity_test',
    string $entity_bundle = 'entity_test',
    string $field_label = 'Test field',
    array $storage_settings = [],
    array $instance_settings = [],
    ?string $widget_type = NULL,
    array $widget_options = [],
    ?string $formatter_type = NULL,
    array $formatter_options = [],
  ): array {
    $entity_type_manager = $this->container->get(EntityTypeManagerInterface::class);
    $entity_display_repository = $this->container->get(EntityDisplayRepositoryInterface::class);

    // Create field storage.
    $field_storage = $entity_type_manager->getStorage('field_storage_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'type' => $field_type,
    ] + $storage_settings);
    $field_storage->save();

    // Create field instance.
    $field_instance = $entity_type_manager->getStorage('field_config')->create([
      'field_storage' => $field_storage,
      'bundle' => $entity_bundle,
      'label' => $field_label,
    ] + $instance_settings);
    $field_instance->save();

    // Configure widget.
    if ($widget_type || $widget_options) {
      if ($widget_type) {
        $widget_options['type'] = $widget_type;
      }
      $entity_form_display = $entity_display_repository->getFormDisplay($entity_type, $entity_bundle);
      $entity_form_display->setComponent($field_storage->getName(), $widget_options)->save();
    }

    // Configure formatter.
    if ($formatter_type || $formatter_options) {
      if ($formatter_type) {
        $formatter_options['type'] = $formatter_type;
      }
      $entity_view_display = $entity_display_repository->getViewDisplay($entity_type, $entity_bundle);
      $entity_view_display->setComponent($field_storage->getName(), $formatter_options)->save();
    }

    return [
      'field_storage' => $field_storage,
      'field_instance' => $field_instance,
    ];
  }
Написанное актуально для
Drupal 11+
Похожие записи

Добавить комментарий