domingo, 21 de outubro de 2012

Teste de condição de erro com PHPUnit


Vamos dizer que você está mantendo o código que utiliza nativa do PHP trigger_error () função para registrar as informações de erro. Vamos dizer também que você está no processo de usar o PHPUnit para escrever testes de unidade para esse código.
Se você consulte o manual do PHPUnit, há uma seção que trata de teste de condição de erro . Ele descreve como PHPUnit implementa seu próprio tratador de erro que converte erros, avisos e avisos em exceções e que a captura essas exceções é como você deve lidar com testes para esses tipos de erros.

No entanto, dependendo do que o seu código se parece, é possível que você vai correr em um problema com a abordagem PHPUnit para isso. Este artigo irá detalhar o que este problema é, como ela afeta a sua capacidade de testar seu código, e como fazer para resolvê-lo.

Qual é o problema?
Erros e exceções se comportar de maneiras fundamentalmente diferentes. De particular relevância para este artigo é o fato de que a execução de código pode continuar no ponto imediatamente após trigger_error () se o nível constante de erro passado para ele não é indicativo de um erro fatal. Quando uma exceção é lançada, a execução continua no início de um bloco de captura encontrado para corresponder à classe desta excepção, que pode ou não estar imediatamente após o ponto em que a exceção é lançada.
Vejamos alguns exemplos desses comportamentos. Em primeiro lugar, os erros.

<? Php
error_reporting (E_ALL | E_STRICT);
echo "Antes de aviso \ n" ;
trigger_error ( "Perigo Will Robinson!" , E_USER_WARNING);
echo "Depois aviso \ n" ;

Você terá a seguinte saída se você executar o código acima:
Antes de advertência
PHP Warning: Perigo Will Robinson! in / home / Matt / error_handler.php na linha 4
Depois da advertência
Daí se vê que o comando echo após o trigger_error () chamada é executado.

Agora, exceções.

<? Php
try {
    echo "Antes de exceção \ n" ;
    lançar nova exceção ( "Perigo Will Robinson!" );
    echo "Depois de exceção \ n" ;
}
catch (Exception $ e ) {
    echo "No bloco catch \ n" ;
}

E a saída:
Antes de exceção
No bloco catch
Em contraste com o caso de exemplo para erros, o código após a exceção foi lançada não é executado. Porque PHPUnit converte erros para exceções, os erros se comportam da mesma maneira em testes de unidade como exceções fazer. Qualquer código que segue um erro que está sendo desencadeada não executado enquanto ele está sendo testado.

Aqui está outro exemplo:
<? Php
função foo ( $ param ) {
    se ( is_string ( $ param )) {
        trigger_error ( __FUNCTION__ . "não suporta mais cordas, passar um array" , E_USER_NOTICE);
    }
    / / Fazer coisas úteis com $ param
    ...
}

Com exceção de erro para a conversão, não há nenhuma maneira de testar se coisas úteis é feito com $ param porque esse código nunca será executado quando o erro é convertido em uma exceção.
Efeitos colaterais do Comportamento do PHPUnit

Esta conversão de erros à exceção faz com que as diferenças de como o código vai se comportar no desenvolvimento e testes de como ele vai se comportar na produção. Aqui está um exemplo:

<? Php
função error_handler ( $ errno , $ errstr ) {
    lançar nova exceção ( $ errstr );
}
set_error_handler ( "error_handler" );

try {
    trigger_error ( "Perigo Will Robinson!" , E_USER_WARNING);
}
catch (Exception $ e ) {
    var_dump (error_get_last ());
}
restore_error_handler ();
trigger_error ( "Perigo Will Robinson!" , E_USER_WARNING);
var_dump (error_get_last ());

Aqui está a sua saída:
NULL
PHP Warning: Perigo Will Robinson! in / home / Matt / exception_converter.php na linha 16
array (4) {
  ["Tipo"] =>
  int (512)
  ["Mensagem"] =>
  string (21) "Perigo Will Robinson!"
  ["Arquivo"] =>
  string (59) "/ home / mate / exception_converter.php"
  ["Linha"] =>
  int (14)
}

O primeiro var_dump () chamada, durante o qual o manipulador de erro personalizada que converte erros para exceções está em vigor, as saídas NULL. O segundo var_dump () chamada, durante o qual manipulador de erro padrão do PHP é, com efeito, envia informações sobre o erro que foi acionado.
Note-se que não é porque um manipulador de erro personalizada é usada que o primeiro var_dump () chamada saídas NULL, mas porque esse manipulador de erro gera uma exceção. Se o manipulador de erro mostrada neste exemplo não fez isso, o primeiro var_dump () chamada teria a mesma saída que o segundo.

A Solução
Precisamos de uma solução que permite a execução de código que está sendo testado para continuar, enquanto ainda permitindo-nos verificar que uma condição de erro foi levantada. Como exemplos acima mostram, permitindo a execução de código para continuar pode ser feito usando um manipulador de erro personalizado que não converter erros para exceções. O que este manipulador de erro deve fazer é em vez de captura de informações de erro para posterior análise com afirmações. Aqui está o que isso pode parecer com isto:

<? Php
classe MyTest estende PHPUnit_Framework_TestCase
{
    privadas erros $ ;

    protegido função setUp () {
        $ This -> erros = matriz ();
        set_error_handler ( matriz ( $ this , "errorHandler" ));
    }

    público função errorHandler ( $ errno , $ errstr , errfile $ , $ errline , $ errcontext ) {
        $ This -> erros [] = compacto ( "errno" , "errstr" , "errfile" ,
            "Errline" , "errcontext" );
    }
    público função assertError ( $ errstr , $ errno ) {
        foreach ( $ this -> erros como $ erro ) {
            se ( $ erro [ "errstr" ] === $ errstr
                && $ erro [ "errno" ] === $ errno ) {
                voltar ;
            }
        }
        $ This -> falhar ( "Erro com nível" . $ errno .
            "Ea mensagem" . $ errstr . "'não foi encontrado em" ,
            var_export ( $ this -> erros, true));
    }

    público função testDoStuff () {
        / / Executar o código que aciona um aviso
        $ This -> assertError ( "Mensagem para o erro esperado" ,
            E_USER_WARNING);
    }
}

setUp () , que é executado antes de cada método de teste, lida com a configuração do manipulador de erro que é apenas mais um método na mesma classe que armazena informações sobre cada erro em uma matriz. Outro método como assertError () são então utilizados pelos métodos de teste como testDoStuff () para realizar afirmações contra que informações de erro e informações de saída de depuração relevantes, como o que erros foram acionados em comparação com o que os erros eram esperados.
Outros tipos úteis de afirmações incluem inversões lógicas (ou seja, afirmando que um erro específico não foi desencadeado), verificação de erros com mensagens que correspondem expressões regulares, ou verificar o número de erros acionados.

Conclusão
Nos casos em que você não se importa sobre o teste que a lógica sequência de um erro provocado ainda é executado, o comportamento padrão do PHPUnit é perfeitamente adequado para suas necessidades. No entanto, é importante que você esteja ciente das implicações de que o comportamento.
Nos casos em que se importam com a execução de tal lógica, é igualmente importante que você saiba a forma de complementar a funcionalidade PHPUnit para facilitar o teste exato de seu código é como condições próximas as de seu ambiente de produção é viável.


A ferramenta de moderação características, bem como ouvir falar, votação, um quadro branco, transferências de arquivos, um bate-papo e, provavelmente, muito mais. Parecia uma escolha adequada.

Por favor, desculpe este artigo a ser um pouco de bala ponto-ish mas eu escrevi a maior parte dela ao ouvir as sessões e eu acho que você vai entender o significado de qualquer maneira.

Diversos aperfeiçoamentos  Fabien Potencier
A filosofia do Symfony 2 é ser o mais flexível possível, mas com padrões sensíveis para que possa ser utilizado para a direita fora da caixa, mas possível de ser alterado para tudo o que você precisa. Symfony 2 agora também se adapta padrões PEAR para permitir uma fácil integração de não symfony-bibliotecas em vez de definir seus próprios padrões.

Tanto quanto possível, foi foi colocado em componentes para se certificar de que eles não dependem do framework MVC e pode funcionar independente. Isso também facilita o uso por novatos Symfony, bem como especialistas.

Fabien introduziu as mais recentes adições à biblioteca de componentes.
CssSelector desenvolvido a partir do zero converte seletor CSS para seus equivalentes XPath.
DomCrawler foi baseada em navegador symfony classe 1 e pode navegar no DOM. Seus métodos são encadeável, pode utilizar CssSelector mas usa XPath internamente e sua API jQuery como se sente.
Navegador é um cliente HTTP implementado em PHP que pode até mesmo gerenciar cookies.
Localizador é totalmente reescrito a partir de sua versão symfony 1 e agora implementa interface Iterator do PHP. É encadeável e fornece fácil de usar filtros de data. As assinaturas de método são padronizados e, em vez de identificadores de arquivo que retorna instâncias SplFileInfo. Ele também pode trabalhar com fluxos como na FWS Amazon S3 Zend córrego.
HttpKernel é um kit de construção de quadro e substitui o RequestHandler anterior. Ele tem uma interface muito simples, com apenas dois métodos getRequest () e tratar (). Ele também inclui um Profiler e as funcionalidades WebDebugToolbar.
Todos os componentes são dissociados e, portanto, plenamente testável.

Com estas e o já conhecido Symfony componentes 2 ainda não está pronto, mas os principais conceitos e filosofia geral não vai mudar mais .

A partir do Q & A no final da sessão, nós aprendemos que a esta altura não haverá ferramenta de migração de symfony 1 a Symfony 2, mas haverá , provavelmente, ser uma camada intermediária, uma vez Symfony 2 está pronto.

No entanto, a API pode mudar a qualquer momento! Então, para uso em produção sf1.4 ainda é recomendado !
A primeira versão alpha prevista para Setembro.

Symfony 2 Atende Propel 1,5 François Zaninotto
Eu realmente não usar Propel, mas eu ainda estava interessado em seus últimos desenvolvimentos.

Propel 1.5 é totalmente compatível com o Propel 1.3 e 1.4. É mais rápido, muito IDE amigável, melhor documentado, tem testes de unidade três vezes mais do Propel 1.3 e é totalmente integrado com o symfony 1.4 sfPropel15Plugin.

Anunciado como uma das características do assassino, vêm as consultas modelo que se supõe ser a SQL que o ActiveRecord é a linha da tabela. Para mim, parecia um clone de Doutrinas DQL mas com nomes de domínio específicos do método ..

Característica do assassino seguinte e faltando em Doctrine 1.2 é a herança de tabela concreto! Mas o nível de dados que é, na verdade, o que significa que Desnormaliza colunas definidas no modelo pai são armazenados nas tabelas filho também por razões de desempenho. Eu realmente não considero que isso seja concreto, mas composto e eu me lembro de ter feito algo semelhante na Doutrina também ..

A característica do assassino terceiro ainda está por vir será o comportamento aggregate_column que utiliza funções de agregação e lojas e mantém os seus resultados em colunas da tabela extra.

Bem, Propel não está morto, mas não estou convencido de seu instinto assassino e, sinceramente, eu estou irritado com toda essa doutrina bashing. Se o Propel ORM é um bom (o que é para muitos usuários), então eu deveria ser capaz de co-existir com outras soluções! Acho que a principal diferença entre Propel 1,5 e Doutrina 2 é que Propel ainda é um ActiveRecord que alguns podem preferir. Não me embora.

Engraçada após a apresentação de uma pesquisa foi configuração se preferir Propel ou Doctrine e quando eu tinha um olhar que era Doutrina favorecendo 76%. http://twtpoll.com/r/545mw5 . Longe de representante, mas divertida.

O que há de novo no 2 Symfony Doutrina Integração Salarial Jonathan
Jonathans sessão não trouxe novidades demais para você quando você seguiu suas palestras e tweets regularmente, mas foi um bom e atualizado wrap up da implementação atual.

Próximo ao DoctrineBundle para Symfony 2 há agora também é um objeto MondoDB pacote Mapper Documento (ODM não ORM!) E um pacote para as Migrações Doutrina amados com funcionalidade inalterado.

Aqui está Doutrinas Arquitetura em poucas palavras.
O DBAL é responsável por gerenciar as conexões e criar / soltando bases de dados e execução DQL a partir da linha de comando.
O ORM tem o EntitiyManager que persiste e recupera entidades. Você pode ter várias instâncias (ou seja, conexão de banco de dados por ação) do mesmo.
Uma entidade é um objeto PHP regular, não. mais magia, limpo e testável, rápida e limitada apenas pelo PHP e agora você pode usar o construtor como você gosta de
Uma coisa pouco agradável que eu gosto é a tarefa nova linha de comando que garante as configurações de produção! Mas também para tarefas de controle de cache são uma boa adição.

DQL agora usa um bom lexer / analisador e tem uma BNF rigorosa que permite erros de sintaxe úteis em vez de efeitos colaterais!

Durante o desenvolvimento, agora você pode mudar seu esquema sem jogar fora o seu banco de dados. Em vez de uma atualização do esquema compara o esquema do banco de dados atual e suas mudanças de esquema atual para atualizar apenas o que é necessário.

O ODM MongoDB compartilha a mesma arquitetura como ORM apenas com um DocumentManager em vez de um EntitiyManager. Sua DocumentManager faz pleno uso da API do MongoDB.

Você pode até mesmo remapear objetos de documento para Entidade e volta durante o desenvolvimento e até mesmo durante a execução. Então, buscar um modelo de banco de dados e salvá-lo em MongoDB deve ser possível.

Atualmente, apenas MongoDB é suportado e não há suporte para o CouchDB ainda.
Finalmente ORM Doutrinas suporta herança tabela de classe, mas depois viu a versão Propel de que eu tenho que tomar mais profundo olhar antes que eu estou espantado.

Unidade e testes funcionais  Fabien Potencier
Symfony 2 mudaram de cal para PHPUnit 3,5 por causa da padronização (prio topo como o quadro é mais fácil de aprender de que maneira). cal na época era uma opção fácil para testes PHP quando o teste de unidade ainda não havia chegado no mundo PHP. Usando Symfony PHPUnit podem agora beneficiar de ainda outra comunidade e de concentração sobre o quadro e algumas melhorias voltou para PHPUnit já.

Enquanto isso é ótimo em si torna-se melhor quando Fabien partes dois melhores práticas.

Não deve haver mais AllTests.php. Em vez disso você pode usar phpunit.xml (tem um atributo de inicialização!).

Não unidade testar seus controladores! Os controladores não são unidade testada, porque eles só devem conter código de cola e sem lógica de negócios.
A estrutura de teste funcional agora tem uma API mais limpa e utiliza componentes DomCrawler e Navegador.

Testes funcionais agora só testar o objeto de resposta, que é exatamente o que você recebe então o pedido é processado pelo seu controlador.

Você pode ter várias instâncias do navegador de modo que você pode até mesmo testar a interação de vários clientes. Mesmo quando você usa uma biblioteca com estados estáticos isso vai funcionar como para cada navegador um processo PHP novo será criado.

Como os testes funcionais estão usando o componente Navegador eles podem até mesmo ser executado em seu ambiente de produção para fins de monitoramento, utilizando o profiler do pedido. Mesmo testando de não symfony-sites é possível!

A nova forma de enquadramento Bernhard Schussek
Depois de toda a experiência com o framework de formulário do symfony um a nova encarnação agora tem uma arquitetura totalmente nova e foi completamente redesenhado para a simplicidade e reutilização.

"Symfony 2 abraça seu modelo de domínio"

Validadores agora validar modelos de domínio e formas.
Os campos do formulário são totalmente conscientes cultura (localizado) e podem ser agrupados para subformulários "leves", que se tornam um widget, como por exemplo, um localizador Google Maps widget.

CollectionFields pode ser usado para adicionar listas de campos de 1-n relações.
O quadro forma é, naturalmente, também uma biblioteca independente que não depende sem Symfony 2.

As restrições podem ser adicionadas usando anotações ou XML ou YAML mesmo usando callbacks em seus modelos para que você possa facilmente implementar restrições dinâmicas.

Se as formas são agora diretamente modelado em objetos de seu domínio, então como você pode fazer formulários incorporados? Bem, você não pode ou pelo menos não como você faz no symfony 1. Por exemplo, se você quer ter um formulário para o registro do usuário com base no modelo de usuário, mas com campos adicionais para termos e condições ou subscrições de boletim informativo, então você tem que criar um novo modelo de registo primeiro. Isto pode parecer um esforço adicional, mas se você pensar sobre isso faz muito mais sentido.

Restrições também podem ser seqüenciado ou seja, para economizar recursos ao validar restrições baratos primeiro antes de validar os mais caros que podem conter uma chamada de serviço web.

HTML 5 campos de entrada ainda não são suportados, mas os formulários e validadores e os campos e tudo o que é totalmente internationalisationable.

Isso soa como algo de realmente olhar para frente como as formas de symfony 1.2 + foram certamente melhor do que as versões anteriores, mas tinha um monte de falhas de projeto que os fazem se sentir unintuitive.

O Symfony característica do assassino 2 ... Fabien Potencier
Eu estava certo!

"Cache on the Edge"
Ainda de acordo com Symfony outro teste de benchmark 2 será muito mais rápido do que o symfony 1 e ainda mais rápido, com mais solicitações simultâneas. Tudo isso é causado pela característica do assassino novo: o cache.

Assim como verniz, Squid ou Akamai Symfony 2 fornece um cache HTTP ou proxy reverso implementado em PHP. Symfony 2 também implementa as especificações relacionadas HTTP e usa os cabeçalhos de cache para controlar o comportamento de cache. Isso significa que você pode facilmente substituir o cache PHP com verniz ou Akamai sem a necessidade de mudar.

E as classes de cache são muito facilmente integrado como eles decoram o kernel. Eles podem, portanto, ser ativado mesmo para testes funcionais.

O que dizer quando partes da página deve ser armazenado em cache menos?
Sim a melhor parte ainda está por vir. Symfony 2 também implementa o Edge Side Include (ESI) especificações escritas por Akamai que podem ser usadas para armazenar partes das páginas de forma diferente dos restantes. Isto é conseguido por a camada de visualização do padrão MVC que pode retornar a cada parcial separadamente, se bem entendi. Você ainda pode usar outros sites como parciais. Bem, eu tenho a digg em isso em algum momento, mas estou completamente maravilhado com a integridade do projeto.

Eu posso ver que o obriga a uma melhor separação das preocupações que você tem que pensar sobre os tempos de seu cache no início do processo. O que é bom.

Para resumir tudo: a camada de cache é separado do quadro. Isso não significa apenas que você pode trocá-lo com outros proxies reversos isso só significa que para cada solicitação de página que pode ser respondida pela camada de cache do kernel do quadro não é sequer iniciado! 2 Symfony também implementa envelhecer-enquanto-revalidate e envelhecer-se o erro. Vá e google, se você não sabe o que é isso, é absolutamente fantástico!

Outra melhor prática aconselhar:
Se você tem que pensar em invalidar o cache, então você provavelmente está usando vencimento em vez de validação. Em outras palavras: para peças dinâmicas que você deve deixar o cache de validar o cache em vez de definir um tempo expirar. Validação de cache em breve vai ser otimizado automaticamente. Estou curioso para saber como isso vai funcionar.

No entanto grande presente para todos os sons, agora você tem que lembrar que tudo ainda é experimental.

Fone: Testically.org

Nenhum comentário :

Postar um comentário

Total de visualizações de página