Claro que isto levou mais tempo do que o previsto, mas consegui este marco, escrevendo e executando um teste funcional completo em Drupal. Não foi um teste fácil, trivial - e o caminho que tomei para implementá-lo destaca as gotchas e dificuldade de escrever tais testes. Também, meu processo provavelmente não é único, e os desafios que enfrentei parecem comuns. Parece-me valioso escrever rapidamente sobre peculiaridades e truques que vi no caminho. Neste artigo, eu presumo que o leitor é um desenvolvedor intermediário Drupal. Não me debruçarei sobre o básico do desenvolvimento drupal.
♪ ♪ ♪ ♪ ♪ ♪
Antes de mais, e isto levou mais tempo do que gostaria de admitir. Existe uma grande diferença entre <?php e <? , sendo este último uma abreviação de conveniência para o código php. Recomendo sempre usar o primeiro. A razão é que o executável php do apache2 (ou nginx) está configurado de forma diferente do executável php da linha de comando. Eles estão configurados nestes dois arquivos, respectivamente:
- /etc/php/8.1/cli/php.ini
- /etc/php/8.1/apache2/php.ini
E mesmo que você possa ativar as tags curtas:
short_open_tag = OnVocê pode esquecer de fazer isso, ou através da multidão de ambientes e servidores, pode ser apenas inconveniente e propensa a erros para definir isso, duas vezes, toda vez. Basta ser avisado que se o seu site renders apenas bem com <? , isso não significa que drush ou testes vai funcionar em tudo.
Um sinal comum de tell-tale deste problema é se você executar drush, ou phpunit, e em vez de saída esperada você vê um descarte de algum código php, particularmente o conteúdo do arquivo settings.php. Isso significa que o interpretador php falhou em ler o arquivo - então, suas tags curtas não estão habilitadas.
Agora que isso está fora do caminho - vamos escrever algum código Drupal!
♪ ♪ ♪ ♪ ♪ ♪
Vamos escrever o código de produção primeiro, e o teste é o segundo. Para os leitores que fazem isso ao contrário: bom para você, mas eu não encontrei muito benefício em fazer isso. Na verdade, se eu estou preso, eu prefiro o código de produção funciona, e eu posso calcular os testes mais tarde. Se eu estou preso em testes e o código de produção não funciona em tudo - eu diria que o próximo passo é re-focar e tentar corrigir erros e escrever código que funciona - isto é, código de produção. E sim, às vezes escrevo código de teste antes do código de produção. Mas muitas vezes, não.
Nós vamos escrever, e testar, um controlador simples que redireciona um url de padrão "/worklogs/{date}" para um nó correspondente com field_date={date} O código é muito simples:
<?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');
}
}
^ isso vai para um módulo, algo que você provavelmente já tem configurado. Meu módulo é chamado de ish drupal module, e o nome segue um formalismo que eu reutilizo em outro lugar.
♪ ♪ ♪ ♪ ♪ ♪
Agora vamos seguir várias iterações de testes, a primeira não funcionou. Comecei com o seguinte teste:
<?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 poder executá-lo, tive de instalar um monte de coisas via compositor.
Nota: Mudei a estabilidade mínima de "estável" para "dev" em composer.json. Isto não deve ser feito na produção.
Emitindo uma combinação de qualquer ou todos os seguintes comandos para instalar as bibliotecas, eventualmente funcionou para mim:
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:^2Obviamente, eu copiei o arquivo phpunit.xml do núcleo, e ajustei alguns valores.
Com isso, eu estava pronto para fazer o teste da seguinte forma:
./vendor/bin/phpunit -c phpunit.xml -d memory_limit=1G web/modules/ish_drupal_module/tests/src/Functional/WorklogsControllerTest.php --debugIsto não funcionou - dando-me um 403 permission denied, em vez do esperado 200 ok. Eu adicionei as asserções que (1) o nó salvo, e (2) o usuário logado, para ter certeza de que estou em um ambiente autenticado.
Aliás, a asserção de fato passou que o nó salvo, não me ajudou!
Em seguida, eu apresentei um monte de loging para ver por que exatamente eu estava recebendo o código 403:
$response = $this->getSession()->getDriver()->getClient()->request('GET', '/worklogs/2025a', [], [], ['max_redirects' => 0]);
echo('+++ $response');
var_dump($response);E ele revelou o problema: campo 'field date' não estava presente no teste! Enquanto o campo estava presente na produção, o banco de dados de produção não é copiado para o ambiente de teste, então os campos criados na UI não estão disponíveis.
O próximo e último passo foi adicionar o campo necessário no teste, e depois disso meu teste passou:
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();
}
...
}.
E assim, todo o meu ficheiro de teste era assim: https://github.com/wasya-co/ish drupal module/blob/0.5.0/tests/src/Functional/WorklogsControllerTest.php
Espero que isto ajude alguém a desenvolver-se melhor em Drupal! Finalmente, estou disponível para o trabalho Drupal baseado em projetos, então se você precisar de algum desenvolvimento Drupal feito, pressione o botão "contatar-nos" em qualquer lugar neste site para entrar em contato.
.^.