Una primera prueba funcional en Drupal 9 (prueba una redireccion en un controlador)

Read this article in:

...por supuesto que esto tomó más tiempo de lo previsto, pero he logrado este hito, escribiendo y ejecutando una prueba funcional completa en Drupal. No fue una prueba fácil, trivial - y el camino que tomé en la implementación destaca las gotchas y la dificultad de escribir tales pruebas. Además, es probable que mi proceso no sea único, y los desafíos que enfrenta parecen comunes. Parece valioso para mí poner una rápida inscripción en los quirks y trucos que vi en el camino. En este artículo, supongo que el lector es un desarrollador intermedio Drupal. No voy a profundizar en lo básico del desarrollo Drupal.

~ ♪♪

Primero lo primero - y esto me llevó más tiempo de lo que me gustaría admitir. Hay una gran diferencia entre י?php y <? , este último es un cortocircuito de conveniencia para el código de php. Te recomiendo siempre usar el primero. La razón es, apache2 (o nginx) php ejecutable se configura de forma diferente del ejecutable de php de línea de comando. Están configurados en estos dos archivos, respectivamente:

  • /etc/php/8.1/cli/php.ini
  • /etc/php/8.1/apache2/php.ini

Y aunque puedas habilitar las etiquetas cortas:

short_open_tag = On

Es posible que se olvide de hacerlo, o a través de la multitud de entornos y servidores, puede ser simplemente inconveniente y propensa a errores para establecer esto, dos veces, cada vez. Sólo se advierta que si su sitio hace bien con <? , no significa que el cepillo o las pruebas funcionen en absoluto.

Un signo común de cuenta de este problema es si se ejecuta drush, o phpunit, y en lugar de la salida esperada se ve un vertedero de algún código de php, en particular el contenido del archivo settings.php. Significa que el intérprete de php no pudo leer el archivo - así que, sus etiquetas cortas no están habilitadas.

Ahora que esto está fuera del camino - vamos a escribir un código Drupal!

~ ♪♪

Primero escribiremos código de producción, y la prueba es segunda. A los lectores que lo hacen a la inversa: bueno para usted, pero no encontré mucho beneficio para hacer eso. De hecho, si estoy atascado, preferiría que el código de producción funcione, y puedo encontrar las pruebas más tarde. Si estoy atrapado en pruebas y el código de producción no funciona en absoluto - diría que el siguiente paso es volver a enfocar e intentar corregir errores y escribir código que funciona - es decir, código de producción. Y sí, a veces escribo código de prueba antes del código de producción. Pero a menudo, no.

Vamos a escribir, y probar, un simple controlador que redirige una url de patrón "/worklogs/{date}" a un nodo correspondiente field_date={date} . El código es bastante simple:

<?php
// web/modules/ish_drupal_module/src/Controller/WorklogsController.php

namespace Drupal\ish_drupal_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\node\Entity\Node;

class WorklogsController extends ControllerBase {

  public function showRedirect($year) {
    $nids = \Drupal::entityQuery('node')
      ->condition('field_date', $year)
      ->range(0, 1)
      ->execute();

    if (!empty($nids)) {
      $nid = reset($nids);
      $node = Node::load($nid);
      return new RedirectResponse($node->toUrl()->toString());
    }
    return new RedirectResponse('/worklog');
  }

}

^ esto entra en un módulo, algo que presumiblemente ya tiene configuración. Mi módulo se llama ish drupal module, y el nombre sigue un formalismo que reutiliza en otros lugares.

~ ♪♪

Ahora sigamos varias iteraciones de pruebas, la primera de las cuales no funcionó. Comencé con la siguiente prueba:

<?php
// web/modules/ish_drupal_module/tests/src/Functional/WorklogsControllerTest.php

namespace Drupal\Tests\ish_drupal_module\Functional;

use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\BrowserTestBase;

class WorklogsControllerTest extends BrowserTestBase {
  protected $defaultTheme = 'stark';
  protected static $modules = ['node', 'ish_drupal_module', 'user'];
  protected $user;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    //                                    permissions, name, is_admin
    $this->user = $this->drupalCreateUser([], NULL, TRUE);
    $this->user->addRole('administrator');
  }

  /**
   * Tests the redirect
  **/
  public function testShowRedirect() {
    $node = Node::create([
      'type' => 'worklog',
      'title' => 'Test Node 2025a',
      'field_date' => '2025a',
      'status' => 1,
    ]);
    $node->save();
    $saved_node = Node::load($node->id());
    $this->assertNotNull($saved_node, 'Node was saved successfully.');

    $this->drupalLogin($this->user);
    $current_user = \Drupal::currentUser();
    $this->assertEquals($this->user->id(), $current_user->id(), 'User is logged in.');

    $this->assertSession()->addressEquals($node->toUrl()->toString());
    $this->assertSession()->statusCodeEquals(200);

    $this->assertSession()->pageTextContains('Test Node 2025a');
  }
}

Para ejecutarlo, tuve que instalar un montón de cosas a través del compositor.

Nota: Cambié la estabilidad mínima de "estable" a "dev" en composer.json. Esto no debe hacerse en producción.

Issuing a combination of any or all of the following commands to install the library, eventually worked for me:

 composer require --dev --no-update symfony/filesystem:4.4.42
 composer require --dev drupal/core-dev:9.5.11 --with-all-dependencies
   composer require --dev behat/mink jcalderonzumba/mink-phantomjs-driver
   composer update -W
   composer update symfony/filesystem:4.4.42 drush/drush -W
   composer require --dev drupal/core-dev -W
   composer require --dev phpspec/prophecy-phpunit:^2

Obviamente, copié el archivo phpunit.xml del núcleo, y ajusté algunos valores.

Con eso, estaba listo para ejecutar la prueba como sigue:

./vendor/bin/phpunit -c phpunit.xml  -d memory_limit=1G web/modules/ish_drupal_module/tests/src/Functional/WorklogsControllerTest.php --debug

Esto no funcionó. 403 permission denied, en lugar de lo esperado 200 ok. Agregué las afirmaciones de que (1) el nodo salvó, y (2) el usuario conectado, para asegurarse de que estoy en un ambiente autenticado.

Por cierto, la afirmación de hecho pasó que el nodo salvó, ¡no me ayudó!

A continuación, presenté un montón de registro para ver por qué exactamente estaba recibiendo el código 403:


$response = $this->getSession()->getDriver()->getClient()->request('GET', '/worklogs/2025a', [], [], ['max_redirects' => 0]);
echo('+++ $response');
var_dump($response);

Y reveló el problema: campo date no estaba presente en la prueba! Mientras el campo estaba presente en la producción, la base de datos de producción no se copia al ambiente de prueba, por lo que los campos creados en la UI no están disponibles.

El siguiente y último paso fue añadir el campo necesario en la prueba, y después de eso mi prueba pasó:

  protected function setUp(): void {
    parent::setUp();

    if (!NodeType::load('worklog')) {
      NodeType::create([
          'type' => 'worklog',
          'name' => 'Worklog',
      ])->save();
    }
    if (!FieldStorageConfig::loadByName('node', 'field_date')) {
      FieldStorageConfig::create([
        'field_name' => 'field_date',
        'entity_type' => 'node',
        'type' => 'string',
      ])->save();
    }
    if (!FieldConfig::loadByName('node', 'worklog', 'field_date')) {
      FieldConfig::create([
        'field_name' => 'field_date',
        'entity_type' => 'node',
        'bundle' => 'worklog',
        'label' => 'Date',
      ])->save();
    }
    
    ...
  }

.

Y así todo mi archivo de prueba parecía así: https://github.com/wasya-co/ish drupal module/blob/0.5.0/tests/src/Functional/WorklogsControllerTest.php

Espero que esto ayude a alguien a desarrollarse mejor en Drupal! Por último, estoy disponible para el trabajo de Drupal basado en proyectos, así que si necesita algo de desarrollo Drupal hecho, golpee el botón "contáctenos" en cualquier lugar de este sitio para llegar.

.^.

Please login to post comments: