quinta-feira, 16 de abril de 2009

Esperando o resultado de uma chamada assíncrona no Watir

Em alguns casos quando uma determinada requisição assíncrona demora para retornar, o teste de aceitação implementado com Watir pode falhar. Principalmente quando os testes estão rodando em alguma ferramenta de integração contínua.

Para evitar essa falha irritante, o usual é colocar alguns sleeps após as ações que disparam as chamadas ajax. Contudo, isso não garante que o teste não vá falhar, especialmente se o sleep for baixo. Em contrapartida se forem colocado muitos sleeps altos poderá haver uma demora muito grande para rodar todos os testes.

Uma solução possível é esperar que um determinado elemento html seja inserido ou removido da página para então continuar executando os testes. Para isso implementei um método genérico que recebe um bloco de verificação. Veja o exemplo de uso dele:

espera { @browser.text.include? 'Ajax retornado' }

O código do método é bem simples e está descrito abaixo. Ele recebe um bloco assumindo que quando este retornar verdadeiro significa que a espera deve terminar, caso contrário ele continuará esperando e verificando, com um timeout de 30 segundos.

def espera
Timeout::timeout(30) do
while not yield
sleep 1
end
end
end

4 comentários:

  1. Evoluí lá esse método pra fazer a espera e o teste com o should do rspec numa chamada só: http://gist.github.com/101783

    ResponderExcluir
  2. Guilherme, apesar de ter ficado interessante, o intuíto do método não é esperar determinado teste passar. Neste caso a idéia é aguardar que determinado retorno ocorra do servidor para então fazer os testes. Um exemplo claro é que poderíamos colocar um div de loading, e fazer a espera pelo desaparecimento desse div, para depois então fazer os asserts.

    Se utilizarmos o método de espera como uma forma de aguardar que determinado assert esteja correto, teremos uma espera maior quando ocorrer um erro, mesmo a requisição já tiver sido retornada.

    ResponderExcluir
  3. É verdade.

    Mas acredito que a versão evoluída possui algumas vantagens:

    1 - Ela continua atendendo todos os casos da versão anterior. Ou seja, o exemplo de esperar pelo desaparecimento do div de loading para depois fazer os asserts funciona normalmente com a nova versão.

    2 - Quando a espera falha, o erro exibido é de Timeout::Error. Na nova versão, chamando o should dentro da espera, o erro exibido é o próprio erro do rspec, mais informativo.

    3 - Os casos em que esperamos uma coisa e depois fazemos assert dessa mesma coisa podem ser simplificados com uma chamada só.

    Resumindo, acredito que com a nova versão podemos fazer tudo que é possível com a versão antiga e ainda temos a vantagem de simplificar alguns casos!

    ResponderExcluir
  4. Mas são exatamente essas as "vantagens" que não acho vantajosas para o método criado. De qualquer forma, o método que foi modificado pode ser utilizado, mas não com o mesmo propósito.

    1- A idéia é não abranger todos os casos, é somente verificar se determinado estado foi alterado.

    2- O erro apesar de parecer mais informativo não diz se realmente ocorreu um timeout porque o ajax não retornou, ou se foi o assert que não retornou corretamente.

    3- A idéia do método não é esperar um determinado estado. Os asserts devem ser feitos depois. Se fizermos o assert como a espera, teremos que esperar todo o timeout, mesmo quando o ajax tiver retornado em uma condição de erro.

    Quanto ao resumo, realmente com a nova versão é possível fazer tudo que a antiga, mas com um certa confusão de qual seria o verdadeiro erro (falta do retorno ajax, ou erro no assert?).

    ResponderExcluir