Mostrando postagens com marcador selenium. Mostrar todas as postagens
Mostrando postagens com marcador selenium. Mostrar todas as postagens

quarta-feira, 11 de fevereiro de 2009

Dicas para escrita e uso de testes

Mantenha TODOS os testes passando e atualizados.

Toda vez antes de dar commit, faça um update e rode toda a suite de testes na sua máquina. Caso algum teste quebre, concerte o que precisa ser concertado antes de mandar para o repositório. Lembre-se que o código pertence a todos. Você pode consultar quem escreveu o código/teste, mas se tem um teste quebrado na sua máquina, é seu dever fazê-lo passar.

Deixar testes desatualizados no sistema pode gerar um efeito de bola de neve e mais na frente atrapalhar muito o desenvolvimento. Além disso manter testes quebrados no sistema certamente vai gerar mais erros e diminuir a confiança da equipe no processo de testes.

Escreva testes atômicos do ponto de vista do sistema.

Cada teste deve ser contido em si. Se o teste depende de algum estado do sistema, busque criar o cenário antes de rodar o teste. (ex: o teste do captcha para o login depende de ter a contagem limpa. Assim limpamos a contagem e rodamos o teste.) Também é uma boa prática limpar a casa depois de usar. Assim quando terminarmos de rodar o teste é importante excluir registros e informações que possam interferir em outros testes.

A classe de teste também deve ser o mais auto-suficiente possível. Não crie interdependências entre testes nem use métodos de outra classe te teste. Isso pode dar sérios problemas e dificuldades de manutenção.

Escreva testes atômicos do ponto de vista das funcionalidades.

A não ser se você estiver fazendo um teste de integração, não escreva testes que testam tudo de uma vez. Teste cada funcionalidade de uma vez. Isso deixa os testes fáceis de manter e os relatórios muito melhores. Lembre que a lista dos testes faz as vezes de uma especificação do negócio em muitos casos.

Por exemplo. Ao invés de escrever: "A listagem deve ser mostrada corretamente." Escreva algo como: "deve mostrar a soma dos valores no campo Valor Total", "deve paginar caso haja mais de 15 registros", etc...

Escreva testes rápidos

Busque manter os testes o mais rápido que for possível. Ao caminhar com o desenvolvimento teremos cada vez mais teste e não queremos que o build fique muito lento. Por isso precisamos economizar ao máximo em cada um dos testes.

No selenium evite expressões como "waitForText" ou "waitFor..." qualquer coisa que você não tenha certeza que não vai aparecer. Busque esperar por elementos certos na página e então dê um assert para ver se ele existe. Um bom elemento para usarmos em requisições de Ajax é o indicador de progresso.

Escreva testes que independam ao máximo da interface

Ao escrever um teste, busque testar elementos que você sabe que não vão ser alterados durante o processo de desenvolvimento. Por exemplo, ao invés de testar por uma mensagem, busque testar por elementos da página que provavelmente não vão mudar com o tempo. Ou então vc pode buscar pela constante que indica o valor da mensagem e não pela string.

Criando testes no PHPUnit/Selenium que rodem com o symfony/doctrine/phing/phpunit

Ingredientes

symfony+doctrine: framework de desenvolvimento e ORM
phpunit: para testes unitários
phing: para fazer o build, rodar os testes, gerar a documentação, lavar a roupa, etc...

Problemas a se Vencer:

O phpunit, quando roda pela linha de comando, não carrega as configurações do projeto do symfony.

Alguns testes do selenium precisam de acesso à api do symfony para configurar o ambiente e ter acesso aonde o browser não tem.

Descrição da Solução:

Para isso precisamos carregar as configurações do symfony/docrine. Claro que é bom fazer isto uma vez só para não pesar nos testes. Porém precisamos fazer isto de uma maneira que não prenda muito os testes a um diretório específico e que não seja repetitiva.

O phpunit, quando rodado pelo phing, não considera as suites de teste, rodando todos os testes separadamente. Por isso, o setUp() da suite, que poderia parecer um bom local, na verdade não é pois ele será desconsiderado pelo phing. Escolhemos então o setUp de cada classe teste. Para não repetir o código, criamos uma classe da qual extendemos todos os nossos testes. Assim nossas classes já herdam o setUp. Como o autoload do symfony ainda não foi carregado, precisamos informar para o phpunit o caminho da nossa classe caso ela não esteja no include.

Solução Proposta:


### classe pai

class Sf_PHPUnit_Extensions_SeleniumTestCase extends PHPUnit_Extensions_SeleniumTestCase {
function setUp()
{
if ( SF_APP_NAME != '' )
{
define( 'SF_APP_NAME', 'frontend' );
define( 'SF_ENV', 'test' );
define( 'SF_CONN', 'doctrine' );
// ajuste o caminho abaixo de acordo com o local onde vc por esta classe
require_once(dirname(__FILE__).'/../../../../config/ProjectConfiguration.class.php');
// busca as configurações do projeto
$configuration = ProjectConfiguration::getApplicationConfiguration( SF_APP_NAME , SF_ENV, true);
sfContext::createInstance($configuration);
sfContext::getInstance()->getUser()->initSession('phpunit');
// em alguns contextos as linhas abaixo podem ser úteis, mas não lembro quais agora :)
//$databaseManager = new sfDatabaseManager($configuration);
//$databaseManager->loadConfiguration();
}

$this->setBrowser("firefox");
// "solução de contorno" para definir se o teste está no ambiente de desenv ou homolog.
if(isset($_SERVER[HOMEDRIVE]) && $_SERVER[HOMEDRIVE] == 'C:') {
$this->setBrowserUrl("http://aliaslocal/");
}
else {
// ip ou alias do servidor...
$this->setBrowserUrl("http://10.1.1.234/");
}
}
}

### classe filha


require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
// lembrar que este require é necessário pois o autoload do symfony ainda não foi carregado neste ponto.
require_once dirname(__FILE__).'/../../../plugins/sfUtil/lib/test/SF_PHPUnit_Extensions_SeleniumTestCase.php';

class LoginSeleniumTest extends SF_PHPUnit_Extensions_SeleniumTestCase
{

function setUp() {
// lembrar de chamar o setUp do pai caso precise extender aqui...
parent::setUp();
$this->doSomeMoreSetup();
}
// ...

Conclusão:

Claro que devem existir inúmeras soluções para este problema. Caso você tenha algo a acrescentar ou alguma crítica construtiva, certamente isto vai melhorar ainda mais a nossa proposta.