Prática recomendada para testes de unidade no Magento 1.9

11

Eu mantenho um site Magento 1.9 com vários módulos personalizados. Algumas das funcionalidades são críticas para os negócios e precisam urgentemente de alguns testes de unidade. Por exemplo, uma calculadora de preço unitário.

Normalmente, desenvolvo no Symfony e realmente preferiria usar o PHPUnit (w / Composer), se possível.

Algumas funcionalidades são baseadas nos dados importados para várias tabelas de banco de dados personalizadas, então eu preferiria carregar os acessórios de alguma forma.

Então, estou procurando a melhor prática para escrever alguns testes de unidade. Vou aceitar aceitar tutoriais ou algo parecido. Qualquer ajuda é apreciada.

frigg
fonte

Respostas:

10

Eu enfrentei o mesmo problema há algum tempo.

Considerei usar o módulo Ecomdev PHPUnit, mas acho difícil de usar e mal documentado (mas ainda amo o que Ivan faz e sua grande contribuição para o ecossistema Magento).

Portanto, com a ajuda do Vinai, acabei desenvolvendo o seguinte módulo de estrutura de teste: https://github.com/digitalpianism/testframework

O objetivo original era para testes de integração, mas também estou sendo usado para testes de unidade. Você pode vê-lo em ação aqui: https://github.com/digitalpianism/easytoplinks/blob/master/app/code/community/DigitalPianism/EasyToplinks/Test/Unit/Block/Page/Template/LinksTest.php

Em relação aos equipamentos, estou usando reversões de transações para evitar a criação de dados de amostra no banco de dados.

Raphael na Digital Pianism
fonte
Isso parece realmente promissor. Vou testá-lo. Obrigado.
Frigg #
13

Instalação

Como o Magento 1 não usa o compositor pronto para uso, não acho que faça muita diferença se você instalar o phpunit usando o compositor ou apenas baixar a versão farmacêutica .
Se você já usa o compositor para gerenciar outros módulos ou bibliotecas de terceiros em seu site, o compositor provavelmente faz mais sentido. A menos que você use o PHP7, você estará limitado a uma versão antiga do phpunit (é por isso que vinculei à versão 4.8 acima).

Testes de integração vs / e / ou testes de unidade

Como o Magento 1 é uma aplicação tão pesada, faz sentido separar o bootstrap do phpunit em um para integração e outro para testes de unidade.
O bootstrap de teste de unidade precisa apenas inicializar o carregador automático, enquanto o bootstrap de teste de integração precisa inicializar todo o ambiente do aplicativo, incluindo o carregamento da configuração e a conexão db.
Por causa disso, os testes de integração no Magento tendem a ser muito mais lentos que os testes de unidade (ainda mais em outras aplicações).

Inicializando o Magento no phpunit

  • O carregador automático do Magento não é compatível com PSR-0, pois gera uma exceção se não conseguir encontrar o arquivo em que a classe está localizada. Isso interrompe alguns usos do class_existsphpunit. Existem várias soluções possíveis (se hacky):

    • Cancele o registro do carregador automático Magento, envolto \Varien_Autoload::autoload()em um decorador, ignorando as exceções lançadas, e registre o wrapper como um novo carregador automático. Isso tem uma baixa chance de conflitos com bibliotecas de terceiros que registram carregadores automáticos e dependem de uma ordem específica do carregador automático.
    • Use um manipulador de erros personalizado que inclua o incorporado no Magento 1. Os manipuladores de erros personalizados engolem os erros acionados pelo carregador automático Magento. Essa é a solução usada pela estrutura de teste do Raphael . Parece ser o mais compatível com outras extensões de terceiros.
    • Use o caminho de inclusão hack para substituir \Varien_Autoload::autoload()para não gerar o erro se o arquivo não existir. No entanto, isso entra em conflito com vários módulos que também substituem a mesma classe. Eu não uso essa abordagem sozinho.
  • Para evitar que os erros da sessão sejam iniciados durante os testes, basta definir $_SESSON = []no bootstrap.

  • Defina um objeto de resposta personalizado via Mage::app()->setResponse($testResponse)que estenda o real, mas não envie saída ou cabeçalhos.

  • Para reinicializar o Magento entre testes de integração que alteram completamente o estado de tempo de execução, use Mage::reset(); Mage::app(). Observe que depois disso, o manipulador de erros precisará ser decorado novamente.

Luminárias

Para luminárias DB, eu costumo usar os modelos regulares nos métodos de luminárias para criar luminárias, por exemplo createSimpleProduct($sku). Como Raphael disse, use setUp()e tearDown()para finalizar o teste em uma transação que é revertida após o teste (por exemplo Mage::getSingleton('core/resource')->getConnection('default_setup')->beginTransaction()).

Para acessórios de configuração de loja, costumo instalar apenas dispositivos de memória usando Mage::app()->getStore()->setConfig($path, $value).

A EcomDev_PHPUnitextensão também fornece a opção de criar acessórios de banco de dados usando arquivos yaml, mas, para mim, acho esses mais difíceis de manter em comparação com os acessórios criados usando classes de modelo. YMMV.

Duplas de teste

O registro pode ser usado para injetar dobras de teste para objetos criados via Mage::getSingleton(), Mage::getResourceSingleton()e Mage::helper().
Alguns outros objetos centrais podem ser ativados Mage::app()(por exemplo, a solicitação).
Para substituir as classes criadas via Mage::getModel()ou Mage::getResourceModel()com teste duplo, um wrapper de objeto de configuração personalizado deve ser usado. Veja este exemplo na estrutura de teste de Raphael, como isso pode ser realizado.

Sumário

Depois que o Magento é inicializado, praticamente tudo pode ser testado de maneira bastante agradável. Esteja preparado para criar zombarias profundas devido à grande quantidade de métodos encadeados que o código principal usa.
Embora a configuração seja hacky, ela funciona bem e acho que os testes me dão muita confiança e valor, comparáveis ​​a uma suíte de testes para um aplicativo Symphony.

Vinai
fonte
Eu nunca tentei, mas por que não usar o Magento Test Framework? ( docs.magento.com/m1/ce/user_guide/magento/… )
Fra
3
Sim, eu tentei, mas é um teste funcional (não de unidade ou integração), é lento, é complexo e os testes tendem a ser escamosos e quebradiços. No geral, considerei o tempo gasto com isso um desperdício.
Vinai
@Vinai Eu sei que é tarde, mas geralmente em um controlador há chamadas para modelos e coleções, que durante o teste não precisaremos. Estou usando sua estrutura de teste (DigitalPianism), e aí podemos testar os modelos, mas, ao fazer uma solicitação get para uma ação do controlador que por sua vez usa um modelo, como posso zombar dessa chamada de modelo / coleção?
Arqam 05/11/19