Eu achei a discussão em Você testa o método privado informativo.
Eu decidi que, em algumas classes, quero ter métodos protegidos, mas testá-los. Alguns desses métodos são estáticos e curtos. Como a maioria dos métodos públicos os utiliza, provavelmente poderei remover os testes com segurança mais tarde. Mas, para começar com uma abordagem TDD e evitar a depuração, eu realmente quero testá-los.
Pensei no seguinte:
- Método Objeto conforme recomendado em uma resposta parece ser um exagero para isso.
- Comece com métodos públicos e quando a cobertura do código for fornecida por testes de nível superior, proteja-os e remova os testes.
- Herdar uma classe com uma interface testável tornando públicos métodos protegidos
Qual é a melhor prática? Mais alguma coisa?
Parece que o JUnit altera automaticamente os métodos protegidos para se tornar público, mas não tive uma visão mais aprofundada. O PHP não permite isso via reflexão .
php
unit-testing
phpunit
GrGr
fonte
fonte
Respostas:
Se você estiver usando PHP5 (> = 5.3.2) com PHPUnit, poderá testar seus métodos privados e protegidos usando reflexão para defini-los como públicos antes de executar seus testes:
fonte
protected
método também faz parte da API pública, porque qualquer classe de terceiros pode estendê-lo e usá-lo sem nenhuma mágica. Então, acho que apenasprivate
métodos se enquadram na categoria de métodos a não serem diretamente testados.protected
epublic
deve ser testado diretamente.Você parece já estar ciente, mas eu vou reafirmar de qualquer maneira; É um mau sinal, se você precisar testar métodos protegidos. O objetivo de um teste de unidade é testar a interface de uma classe, e métodos protegidos são detalhes de implementação. Dito isto, há casos em que faz sentido. Se você usar herança, poderá ver uma superclasse como fornecendo uma interface para a subclasse. Então, aqui, você teria que testar o método protegido (mas nunca privado ). A solução para isso é criar uma subclasse para fins de teste e usar isso para expor os métodos. Por exemplo.:
Observe que você sempre pode substituir herança por composição. Ao testar o código, geralmente é muito mais fácil lidar com o código que usa esse padrão; portanto, convém considerar essa opção.
fonte
o teastburn tem a abordagem correta. Ainda mais simples é chamar o método diretamente e retornar a resposta:
Você pode chamar isso simplesmente em seus testes:
fonte
Eu gostaria de propor uma pequena variação para getMethod () definido na resposta de uckelman .
Essa versão altera o getMethod () removendo valores codificados e simplificando um pouco o uso. Eu recomendo adicioná-lo à sua classe PHPUnitUtil como no exemplo abaixo ou à sua classe de extensão PHPUnit_Framework_TestCase (ou, suponho, globalmente ao seu arquivo PHPUnitUtil).
Como o MyClass está sendo instanciado de qualquer maneira e o ReflectionClass pode usar uma string ou um objeto ...
Também criei uma função de apelido getProtectedMethod () para ser explícito o que é esperado, mas isso depende de você.
Felicidades!
fonte
Acho troelskn está perto. Eu faria isso:
Em seguida, implemente algo como isto:
Você então executa seus testes no TestClassToTest.
Deveria ser possível gerar automaticamente essas classes de extensão analisando o código. Eu não ficaria surpreso se o PHPUnit já oferecer esse mecanismo (embora eu não tenha verificado).
fonte
Vou jogar meu chapéu no ringue aqui:
Eu usei o __call hack com graus variados de sucesso. A alternativa que eu criei foi usar o padrão Visitor:
1: gerar uma classe personalizada ou stdClass (para aplicar o tipo)
2: prepare isso com o método e argumentos necessários
3: verifique se o seu SUT possui um método acceptVisitor que executará o método com os argumentos especificados na classe visitante
4: injete na classe que você deseja testar
5: SUT injeta o resultado da operação no visitante
6: aplique suas condições de teste ao atributo de resultado do Visitante
fonte
Você pode realmente usar __call () de maneira genérica para acessar métodos protegidos. Para poder testar esta classe
você cria uma subclasse em ExampleTest.php:
Observe que o método __call () não faz referência à classe de forma alguma, portanto você pode copiar o acima para cada classe com os métodos protegidos que deseja testar e apenas alterar a declaração da classe. Você pode colocar essa função em uma classe base comum, mas eu não tentei.
Agora, o caso de teste em si difere apenas no local em que você constrói o objeto a ser testado, trocando ExampleExposed por Example.
Acredito que o PHP 5.3 permita que você use a reflexão para alterar diretamente a acessibilidade dos métodos, mas presumo que você precise fazer isso para cada método individualmente.
fonte
call_user_method_array()
função está obsoleta a partir do PHP 4.1.0 ... use em seucall_user_func_array(array($this, $method), $args)
lugar. Note que se você estiver usando PHP 5.3.2+ você pode usar o reflexo para ter acesso a protegidas métodos / privadas e atributosAccessible
pacote genérico que usa reflexão para permitir que testes acessem propriedades e métodos privados / protegidos de classes e objetos.__call()
só é chamado se o chamador não tiver acesso ao método. Como a classe e suas subclasses têm acesso aos métodos protegidos, as chamadas para eles não serão atendidas__call()
. Você pode postar seu código que não funciona no 5.2.7 em uma nova pergunta? Eu usei o acima em 5.2 e só mudei para usar reflexão com 5.3.2.Sugiro que você siga a solução alternativa para a solução / idéia de "Henrik Paul" :)
Você conhece nomes de métodos particulares de sua classe. Por exemplo, eles são como _add (), _edit (), _delete () etc.
Portanto, quando você quiser testá-lo a partir do aspecto do teste de unidade, basta chamar métodos privados prefixando e / ou sufixando alguma palavra comum (por exemplo, _addPhpunit) para que quando o método __call () for chamado (já que o método _addPhpunit () não existe) da classe do proprietário, basta colocar o código necessário no método __call () para remover as palavras com prefixo / sufixo (Phpunit) e depois chamar esse método privado deduzido a partir daí. Este é outro bom uso de métodos mágicos.
Experimente.
fonte