Menu
X

Testando seu código jQuery com Jasmine – Parte 2

Nesta segunda parte você conhece um pouco mais sobre o framework de testes Jasmine. Aprenda a criar matchers personalizados e testar AJAX e métodos em objetos.

0
Imagem post: Testando seu código jQuery com Jasmine – Parte 2

Jasmine é um framework para testes focado em BDD (Behavior Driven Development). Na primeira parte deste artigo aprendemos seus métodos básicos e realizamos alguns testes simples. Agora chegou a hora de ir um pouco além e conhecer técnicas mais avançadas.

Vale lembrar que, em nossos exemplos, utilizamos uma versão modificada da biblioteca, adaptada para jQuery: jasmine-jquery.

Utilizaremos os dados de um outro artigo, Conteúdo sob demanda com jQuery. O objetivo é testar as solicitações AJAX do carregamento da lista de tweets do Tableless.

Fixtures

Antes dos testes propriamente ditos vamos conhecer uma forma prática de carregar nosso conteúdo HTM. Fixtures são arquivos carregados através do método loadFixtures. Esta funcionalidade, aliás, está disponível apenas no jasmine-jquery.

Vamos salvar o código HTML abaixo no arquivo tweets.html, dentro do diretório de fixtures.

[cce lang="xml"]
<div id=”container”>
<h1>Tweets do Tableless</h1>
<ul id=”lista-tweets”></ul>
<p><a href=”#” id=”carrega-tweets” data-pagina=”1″>Mais!</a></p>
</div>
[/cce]

Por padrão, o jasmine-jquery procura as fixtures no diretório spec/javascripts/fixtures. Como na primeira parte do artigo indicamos uma estrutura diferente, utilizando o diretório spec/fixtures, precisamos atualizar a propriedade fixturesPath nas configurações do Jasmine.

[cce lang="javascript"]
jasmine.getFixtures().fixturesPath = ‘spec/fixtures/’;

describe(‘Exibição dos últimos tweets do Tableless’, function(){
beforeEach(function(){
loadFixtures(‘tweets.html’);
});

it(‘Deve carregar na primeira página’, function(){
expect($(‘#carrega-tweets’).data(‘pagina’)).toEqual(1);
});
});
[/cce]

Outra forma de utilizarmos fixtures é carregando diretamente no código, sem a necessidade de um arquivo HTML. Esse caso é mais indicado para templates mais simples, com poucos elementos.

[cce lang="javascript"]
setFixtures(‘<ul id=”lista-tweets” />’);
[/cce]

Testando código assíncrono

Testar código AJAX pode ser um pouco mais complicado. No nosso exemplo, como acessamos uma URL externa à nossa aplicação, o tempo de resposta vai depender de vários fatores, como velocidade da conexão, estabilidade do Twitter etc.

Os métodos runs e waits são úteis para tentar simular esse tempo de carregamento. O runs executa os testes e funções um escopo próprio e, além disso, são executados em sequência (quando um termina, o outro começa). Já o método waits funciona como uma espécie de pausa/sleep e recebe como parâmetro o tempo em milissegundos.

[cce lang="javascript"]
it(‘Deve carregar os últimos 20 tweets’, function(){
runs(function(){
Tableless.retorna_tweets(1);
});
waits(1500);
runs(function(){
expect($(‘#lista-tweets li’).length).toEqual(20);
});
});
[/cce]

Espionando métodos

Às vezes precisamos testar se um método de um objeto é chamado (e com que parâmetros) — e não testar apenas seu resultado. O Jasmine oferece a função spyOn para capturar e validar essas chamadas. O spyOn recebe dois parâmetros: o objeto e o nome do método.

[cce lang="javascript"]
it(‘Deve executar função para retornar tweets’, function(){
spyOn(Tableless, ‘retorna_tweets’);
Tableless.retorna_tweets(1);
expect(Tableless.retorna_tweets).toHaveBeenCalledWith(1);
});
[/cce]

Acima testamos se o método foi chamado com o parâmetro 1 (página). Poderíamos ter utilizado também toHaveBeenCalled, testando apenas a chamada. As funções de spy podem ainda ser combinadas com o not, por exemplo:

[cce lang="javascript"]
expect(Tableless.retorna_tweets).not.toHaveBeenCalled();
[/cce]

Matchers personalizados

Outra funcionalidade poderosa do Jasmine é a possibilidade de criação de matchers personalizados. Os matchers são asserts para seus tests. No exemplo abaixo, criamos o matcher toBeATweet para validar se um elemento possui a classe “tweet”.

[cce lang="javascript"]
beforeEach(function(){
this.addMatchers({
toBeATweet: function(){
return this.actual.hasClass(‘tweet’);
}
});
});
[/cce]

[cce lang="javascript"]
expect($(‘#lista-tweets li:first’)).toBeATweet();
[/cce]

O método addMatchers deve ser executado dentro do beforeEach, utilizando o Jasmine como contexto. Notem que ele recebe um objeto que pode conter um ou mais matchers personalizados. No código, this.actual representa a variável, elemento, ou objeto que estará sendo passado ao expect.

Outros projetos utilizando Jasmine

Nesses dois artigos vocês conheceram o jasmine-jquery, mas existem diversos outros projetos baseados no framework Jasmine, incluindo adaptações para NodeJS, Rails e iPhone e snippets para Vim e TextMate. A lista completa você confere no wiki do projeto no Github.

Referências