Executando verificação de segurança...
2

🔬 Lidando com Testes de Unidade e Declarações de Tipo em PHP

O Cenário: 🐕🧪

Durante meus estudos com testes de unidade em PHP com o PhpUnit, deparei-me com um desafio intrigante que desejo compartilhar. O cenário envolve a criação da classe "Dog" e a implementação de testes para garantir que a função "call" funcione de maneira esperada. Essa jornada tem como objetivo aprimorar minhas habilidades e práticas de programação.

Comecei desenvolvendo uma função de teste simples, que deveria lançar uma exceção quando um tipo de parâmetro inválido fosse fornecido. Infelizmente, a função de teste não produziu os resultados esperados, levando-me a investigar o motivo desse comportamento inesperado.

A função de Teste:

public function testWhenCallsDogWithInvalidTypeMustHaveException(): void
{
    $dog = new Dog('Bob');
    $this->expectException(TypeError::class);
    $dog->call(11111);
}

Minha função "call" foi inicialmente implementada da seguinte forma:

public function call(string $name): bool
{
    return $name == $this->name ? true : false;
}

No entanto, observei que, apesar de ter definido o tipo do parâmetro como "string", o PHP tentava forçar a conversão do argumento para uma string em vez de lançar uma exceção quando um tipo inválido era fornecido. Isso acontece devido à coerção automática de tipos do PHP.

A Solução Proposta: 🛠️🧪

Decidi validar manualmente o tipo do parâmetro e lançar uma exceção quando necessário (apesar de pensar que a declaração de tipo no parâmetro já servisse para isso):

public function call(string $name): bool
{
    if (!is_string($name)) {
        throw new \TypeError('The call() function expects a string argument.');
    }
    return $name == $this->name ? true : false;
}

Então eu rodei o teste novamente, muito feliz e contente mas a função de teste não passou.

A Descoberta Surpreendente: 🤯❗

Acreditei que ao declarar no início do arquivo declare(strict_types=1);, poderia garantir que o PHP seguisse as declarações de tipo estritas e lançasse um TypeError quando houvesse uma discrepância.

No entanto, mesmo com essa declaração, meu teste ainda não passou.

A Experiência de Depuração: 🔍🐞

Para entender o motivo, criei um ambiente de teste online que reproduzisse a situação:

<?php
declare(strict_types=1);

class Dog
{
    public function __construct(private string $name) {}

    public function call(string $name): bool
    {
        return $name == $this->name ? true : false;
    }
}

try {
    echo (new Dog('Max'))->call(12) == true ? "Dog came to me" : "Dog did not come to me";
} catch (TypeError $e) {
    echo "It threw on TypeError. \n";
}
?>

No entanto, nesse ambiente isolado, a exceção estava sendo lançada como esperado.

**A Busca Pela Resposta: ** 🔍📝

Após mais pesquisas, descobri que a declaração declare(strict_types=1); afeta apenas as chamadas de funções feitas no escopo do arquivo. Como meu teste utiliza o método call da classe "Dog", que não está no escopo global do arquivo, a declaração de tipos estritos não afeta seu comportamento.

A Conclusão: 💡

A razão pela qual o teste não passa está na natureza da declaração declare(strict_types=1);. Para garantir a aplicação de declarações de tipo estritas, elas devem ser utilizadas na própria função que está sendo testada.

Minha jornada de aprendizado nesse desafio me lembrou da importância de compreender a abrangência das declarações de tipo estritas em PHP e como elas impactam as diferentes partes do código.

Carregando publicação patrocinada...