Phpunit: assertType() invocando autoloader para tipos escalares

Criado em 23 nov. 2010  ·  10Comentários  ·  Fonte: sebastianbergmann/phpunit

Ao usar assertType() para verificar se um valor é um array ou um valor escalar, o autoloader é invocado (como efeito colateral do uso de class_exists()). Seria bom verificar primeiro se o parâmetro de string de tipo esperado corresponde a "array" ou a um tipo escalar.

Exemplo:

$this->assertType('array', array());

Esperado: verdadeiro, sem invocar o autoloader
Actual: true, invocando o autoloader para uma classe chamada "array"

Comentários muito úteis

Por favor, use assertInternalType() em vez de assertType() para tipos internos.

Todos 10 comentários

Por favor, use assertInternalType() em vez de assertType() para tipos internos.

Isso funciona, mas por que isso é necessário?

Aqui está o código de assertType:

public static function assertType($expected, $actual, $message = '')
{
    if (is_string($expected)) {
        if (PHPUnit_Util_Type::isType($expected)) {
            if (class_exists($expected) || interface_exists($expected)) {
                throw new InvalidArgumentException(
                  sprintf('"%s" is ambigious', $expected)
                );
            }

Parece-me que PHPUnit_Util_Type::isType já testa se o tipo é um tipo interno, então tudo o que você precisaria mudar é isso:

            if (class_exists($expected, false) || interface_exists($expected, false)) {

para desabilitar o autoloader para tipos internos. o que estou perdendo?

Eu tenho que concordar com arnoschaefer, por que você está exigindo que usemos uma função diferente quando sua solução é suficiente? Não estou alterando milhares de testes de unidade já existentes que usam assertType do < 3.5. Portanto, substituirei assertType para todos os meus testes de unidade com esta solução. Acho que merecemos uma explicação melhor por que você escolheu esse caminho, caso contrário vou ter que declarar phpunit FAIL.

Um único método de ativação não pode implementar as duas funcionalidades diferentes. Foi meu erro supor inicialmente que era possível. É por isso que assertInternalType() existe agora.

Por favor, forneça uma explicação de por que um único método de asserção não pode implementar as duas funcionalidades diferentes?

Além disso, sua documentação contradiz esta afirmação:

http://www.phpunit.de/manual/3.5/en/api.html#api.assert.assertType :

Alternativamente, $expected pode ser uma dessas constantes para indicar um tipo interno:

* PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY ("array")
* PHPUnit_Framework_Constraint_IsType::TYPE_BOOL ("bool")
* PHPUnit_Framework_Constraint_IsType::TYPE_FLOAT ("float")
* PHPUnit_Framework_Constraint_IsType::TYPE_INT ("int")
* PHPUnit_Framework_Constraint_IsType::TYPE_NULL ("null")
* PHPUnit_Framework_Constraint_IsType::TYPE_NUMERIC ("numeric")
* PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT ("object")
* PHPUnit_Framework_Constraint_IsType::TYPE_RESOURCE ("resource")
* PHPUnit_Framework_Constraint_IsType::TYPE_STRING ("string")

Sua nota abaixo apenas "recomenda" que assertInternalType deve ser usado e que não é obrigatório:

Observação

Recomenda-se usar assertInternalType (consulte a seção chamada “assertInternalType()”) em vez de verificar os tipos internos.

Um único método de asserção não pode implementar as duas funcionalidades diferentes porque elas são ambíguas. Digamos que você tenha uma classe chamada String e use assertType("string", ...) -- como o PHPUnit deve saber o que você quer?

A recomendação é exatamente para o caso que você está enfrentando: você está usando um autoloader e quer usar assertType() . Isso não funciona.

Enquanto o php permite que uma classe seja chamada de inteiro ou string, seu código atualmente não permite que uma classe seja chamada de string, integer, etc, pois lançaria uma exceção de argumento inválido (%s é ambíguo).

O problema é que se você não definir o parâmetro autoload como false nas funções class_exists e interface_exists na linha 1208, o autoloader tentará incluir um arquivo que não existe (por exemplo class.array.php) e lançará um erro de php em vez de uma exceção.

Fazer essa modificação permitirá que assertType seja usado como sempre foi.

Não, não vai. Porque então outras pessoas vão gritar comigo / PHPUnit porque esperam que o autoload carregue automaticamente sua classe String .

Aqui está o meu conselho, é pegar ou largar:

Não use assertType() . Ele está obsoleto (embora eu tenha esquecido de marcá-lo como tal) e desaparecerá eventualmente. Ele só existe nas versões atuais do PHPUnit para facilitar a migração.

Use assertInternalType() para afirmar que uma variável tem um tipo interno especificado.

Use assertInstanceOf() para afirmar que um objeto tem um tipo especificado (classe ou interface).

Não tenho problemas com uma função obsoleta, mas você não está facilitando a migração. Você mudou a funcionalidade original do phpunit 3.4 que não tinha essa exceção em primeiro lugar e agora está quebrando meu código em vez do cara que carrega automaticamente a classe String. Então eu acho que você deve removê-lo completamente no phpunit 3.5 ou revertê-lo de volta para a funcionalidade 3.4.

Acalme-se, não há necessidade de ficar animado. Eu, pelo menos, posso viver com a decisão de Sebastian, realmente faz sentido, é bom saber o motivo por trás disso. Então eu estarei usando as outras duas funções no futuro. Por outro lado, se assertType está obsoleto de qualquer maneira, por que não mantê-lo funcionando como antes e documentar claramente que está obsoleto, sujeito a remoção em algum momento no futuro. Mas é claro que isso é uma decisão de Sebastian, pois esse é o caminho do software livre.

Esta página foi útil?
0 / 5 - 0 avaliações