Você está na página 1de 4

: : www.mundoj.com.

br : :

Cares Vinicius
(caires.santos@caelum.com.br): desenvolvedor e consultor pela
Caelum nas linguagens em Java, Ruby e Javascript. Entusiasta de
usabilidade para Web e Javascript Server-side.
Lucas Souza
(lucas.souza@caelum.com.br): bacharel em Engenharia da
Computao pela Universidade de Ribeiro Preto, possui a
certificao SCJP e trabalha com Java h 4 anos. Atualmente
desenvolvedor e instrutor pela Caelum. Entusiasta de metodologias
geis e editor-chefe do InfoQ Brasil.

Testando seus cdigos


JavaScript: A importncia e a
facilidade de cri-los
Aprenda como escrever testes de unidade para o lado
cliente da sua aplicao
A linguagem JavaScript tem se tornado a principal
nas aplicaes conhecidas como rich applications ou
aplicaes web 2.0. Porm ainda no tem recebido a
devida ateno quando o assunto diz respeito a testes
automatizados. No artigo ser mostrado na prtica
a importncia e a relevncia de se criar testes para
seus cdigos JavaScript, mostrando ferramentas que
permitem a criao de simples testes de unidade, at a
criao de mocks simulando dependncias complexas.

digo JavaScript tem se tornado cada vez mais frequente


em aplicaes web ricas, as ditas aplicaes web 2.0.
Bibliotecas como jQuery, Prototype, Mootools e outras
facilitam muito o trabalho dos desenvolvedores. Porm o cdigo
muitas vezes acaba no recebendo a ateno necessria, e os problemas so descobertos ou pelos usurios das aplicaes ou pelos
desenvolvedores quando utilizam ferramentas de debugging no
estilo do Firebug. Mesmo com essas ferramentas e com a correo
de erros sendo feita frequentemente, no temos muito cuidado
no processo de isolar determinados cdigos assim como feito
quando nos referimos a cdigos no server side.
O cdigo termina como uma big ball of mud, ou uma grande
bola de lama, onde misturamos cdigos que manipulam a rvore DOM, cdigo de chamadas Ajax para o servidor. Quando
46

precisamos alterar estes cdigos temos uma dificuldade imensa.


Em relao a nossa aplicao, a primeira opo prioriza a funcionalidade, isto , deve funcionar com ou sem javascript. Essa
soluo conhecida como Graceful Degradation. Garantir que a
aplicao funcione sem javascript vai gerar uma perda de usabilidade.
O objetivo do artigo mostrar que testes em cdigos JavaScript
so fceis de fazer e hoje em dia existem muitas ferramentas que
nos auxiliam em processos complexos, como a criao de mocks e
stubs, alm da integrao destes testes com servidores de integrao contnua. Com isso, obtemos cdigos mais legveis e coesos e,
evidentemente, com menor nmero de bugs.

Testes de unidade com QUnit


Vamos primeiro simular um cenrio no qual devemos calcular
alguns impostos e mostrar o resultado para o usurio. Poderamos
resolver o problema de duas maneiras:
Uma requisio no server side para calcular nosso imposto e retornar a pgina preenchida com o valor.
Um cdigo JavaScript que calcula o valor do imposto, sem nenhuma requisio feita no server side.
Pensando em cada vez mais melhorar a usuabilidade e a experincia do usurio em relao a nossa aplicao, ou seja, pensando
na questo do graceful degradation, a primeira opo mais recomendada. Porm, uma soluo que possui um problema, que
pode ser uma resposta lenta ao usurio.
Neste caso, fazendo o clculo atravs de um cdigo JavaScript
deixaria a aplicao mais rpida pelo fato de no ter que fazer
uma requisio e esperar a resposta do servidor, evitando tambm
trfegos desnecessrios pela rede.
Quando no testamos, perdemos qualidade. Com JavaScript no
diferente, e se no testarmos, podemos colocar um valor errado
que pode prejudicar a parte financeira que utiliza sua aplicao
ou no exibir um elemento HTML que deveria aparecer e no
aparece. O teste tambm para garantir essa qualidade.
Em nosso primeiro cdigo, adotaremos a abordagem de TestDriven Development, que uma excelente prtica de desenvolvimento, e que j seguida fortemente quando testamos cdigos
server side. Vamos comear pela criao de um teste e depois
escreveremos o cdigo javascript para que este teste passe.
Utilizaremos uma ferramenta de testes chamada QUnit, que
muito semelhante ao JUnit utilizado para testes de unidade em
Java. O QUnit a ferramenta escolhida pelo conhecido projeto
JQuery para efetuar os testes da sua implementao e tambm dos
plugins existentes para ele. Mas tambm pode ser utilizado para
testar cdigos JavaScript que no utilizam JQuery, exatamente o
que confere com o nosso cenrio.
Para criarmos nosso teste utilizando o Qunit, basta escrever o
HTML da Listagem 1, e dentro da tag <script> colocar a funo onload. Dentro da funo onload, ficam as asseres que desejamos
efetuar. Um detalhe que neste arquivo incluiremos o arquivo
impostos.js, que contm a funo que desejamos testar. Tambm
est incluso a importao de um arquivo css do prprio QUnit
para fazer a formatao do HTML retornado. Na tag <body> so
includos alguns elementos HTML onde o QUnit exibir os resultados dos nossos testes.
Nosso teste falha porque ainda no implementamos a funo
"calcula". Para calcular o valor com os impostos precisamos de
trs informaes: valor, valor do imposto e uma taxa administrativa. No nosso caso, vamos fazer uma multiplicao e uma
adio como frmula para o clculo do nosso imposto. Sabendo
quais argumentos e qual a frmula do clculo do imposto, vamos
implementar nossa funo dentro do arquivo impostos.js, assim
como feito na Listagem 2.

Listagem 1. Criao do teste utilizando Qunit.


<html>
<head>
<link rel=stylesheet href=qunit.css type=text/css media=screen />
<script type=text/javascript src= qunit.js></script>
<script type=text/javascript src=impostos.js></script>
<script>
window.onload = function() {
test(calcula imposto corretamente, function() {
equals(5.7, Imposto.calcula(10.20, 0.5, 0.6));
});
}
</script>
</head>
<body>
<h1 id=qunit-header>QUnit example</h1>
<h2 id=qunit-banner></h2>
<h2 id=qunit-userAgent></h2>
<ol id=qunit-tests></ol>
</body>
</html>

Listagem 2. Criao do clculo de impostos.


Imposto.calcula = function(valor, imposto, taxa) {
return (valor * imposto) + taxa;
}

Se executarmos em nosso browser favorito, o cdigo presente na


Listagem 1, perceberemos que ele nos retorna uma mensagem de
erro, dizendo que nosso cdigo falhou. Isto ocorre por causa do
arredondamento do ponto flutuante do Javascript. Ao invs de
retornar 5.7, nossa funo retorna o valor 5.699999999999999.

O que aconteceu no cdigo acima um problema que pode ser


considerado crnico em relao a arredondamentos em linguagens de programao, por exemplo, a linguagem Java. A linguagem JavaScript tambm tem problemas com arredondamento de
pontos flutuantes.
Percebemos este problema apenas porque nosso cdigo Javascript
recebeu a devida ateno e criamos um teste de unidade para
um clculo que parecia simples, mas que poderia causar grandes
transtornos.
Mas como podemos resolver este problema? Existe alguma soluo nativa do JavaScript? JavaScript possui uma biblioteca
que faz algo similar ao BigDecimal: a classe BigNumber (http://
jsfromhell.com/classes/bignumber). Esta classe JavaScript resolve
nosso problema e faz nosso teste passar, garantindo uma melhor
47

: : www.mundoj.com.br : :

preciso em clculos com pontos flutuantes. Basta alterarmos a


implementao do cdigo presente na funo calcula. O cdigo
utilizando a classe BigNumber mostrado na Listagem 3.
Listagem 3. Clculo de impostos utilizando BigNumber.
Imposto.calcula = function(valor, imposto, taxa) {
var valorComImposto = new BigNumber(valor).
multiply(imposto);
return Number(new BigNumber(taxa).add(valorComImposto));
}

Utilizando a classe BigNumber e executando o teste novamente,


ele passar.

Porm existe outra maneira de corrigir nossa funo utilizando o


mtodo toFixed() do prprio Javascript, que formata um nmero
usando a notao de um ponto fixo. Utilizando o toFixed nosso
cdigo ficaria como o descrito na Listagem 4.
Listagem 4. Clculo de impostos utilizando toFixed.

Listagem 5. Mock de Ajax com ScrewUnit e Smoke.


<html>
<head>
<script src=jquery-1.3.2.js></script>
<script src=jquery.fn.js></script>
<script src=jquery.print.js></script>
<script src=screw.builder.js></script>
<script src=screw.matchers.js></script>
<script src=screw.events.js></script>
<script src=screw.behaviors.js></script>
<script src=smoke.core.js></script>
<script src=smoke.mock.js></script>
<script src=smoke.stub.js></script>
<script src=smoke.ajax.js></script>
<link rel=stylesheet href=screw.css>
<script type=text/javascript>
Screw.Unit(function() {
describe(Faz um requisicao Ajax e retorna um html como
sucesso, function() {
it(mockando uma requisicao ajax com sucesso, function() {
Smoke.Ajax.mock(/meuRecurso, <p>Parabens!</p>, 200);
var resultado, httpStatus;
$.ajax({
url:/meuRecurso,
success: function(data, textStatus){
resultado = data;
httpStatus = textStatus;
},
error: function(error){
resultado = error.responseText;
httpStatus = error.status;
}

Imposto.calcula = function(valor, imposto, taxa) {


return ((valor * imposto) + taxa).toFixed(2);
}
});

Testes de unidade com DOM, Ajax e Callbacks


utilizando Screw.Unit e Smoke
Bibliotecas como jQuery nos ajudam a manipular a rvore DOM e
principalmente a fazer requisies Ajax, que a rotina mais comum
para a grande maioria dos desenvolvedores, mas mesmo sendo
muito corriqueira poucos testam e tomam o cuidado necessrio.
Como testaramos nossa requisio Ajax? Como verificamos se o
elemento HTML foi alterado? Fazendo uma requisio de verdade?
Para testes com Ajax temos a opo de criar objetos falsos, mais
conhecidos como mocks, que simulem a requisio e que faam a
verificao se a mesma foi feita com sucesso, simulando seu mtodo
de callback de sucesso ou simulando uma requisio e um possvel
erro no server side execute o seu mtodo de callback de erro.
Para os exemplos de testes de Ajax usaremos o Screw.Unit como biblioteca de testes e Smoke como biblioteca de Mock. O Screw.Unit
e o Smoke so duas bibliotecas ativas e existem inmeros forks dos
projetos presentes no Github. Utilizaremos como exemplo os fork
de rsutphin e drogus, respectivamente. Nosso primeiro exemplo
(Listagem 5) mostrar a criao de uma requisio Ajax, que simula
o retorno de um cdigo HTTP 200, para indicar sucesso e tambm
o retorno de um HTML com uma mensagem de sucesso dentro de
uma tag <p>.

48

wait(function(){
expect(resultado).to(equal, <p>Parabens!</p>);
expect(httpStatus).to(equal, success);
}, 50);
});
});
</script>
</head>
<body></body>
</html>

Um teste simples para verificar se a resposta que o server side nos


enviou est correta quando o status da requisio sucesso. Neste
primeiro exemplo, testamos o caso de sucesso da requisio, mas
e quando essa requisio no feita com sucesso, o que deve
acontecer?
Em nosso exemplo deve ser retornado um status 500 do HTTP
e tambm um HTML dentro de uma tag <p> como alguma mensagem de erro. Vamos simular este comportamento e testar se o
retorno est correto. Basta adicionarmos mais um comportamento
de teste, atravs da funo it(). Esta nova verificao ser feita na
Listagem 6.

Listagem 6. Testando o caso de erro.


it(mockando uma requisicao ajax com erro, function() {
var resultado, httpStatus;
Smoke.Ajax.mock(/produto, <p>Oops</p>, 500);
$.ajax( {
url : /produto,
success : function(data, textStatus) {
resultado = data;
httpStatus = textStatus;
},
error : function(error) {
resultado = error.responseText;
httpStatus = error.status;
}
});
wait(function() {
expect(resultado).to(equal, <p>Oops</p>);
expect(httpStatus).to(equal, 500);
}, 50);
});

No exemplo acima, definimos dentro do mtodo wait, que ele


deve retornar na varivel resultado um valor igual a "<p>Oops</
p>" e dentro da varivel httpStatus, um cdigo igual a 500. Apenas
simulamos o comportamento da requisio Ajax usando um mock.
O exemplo que utilizamos foi apenas para demonstrar a possibilidade que o Smoke junto ao Screw.Unit nos oferece para usar um
mock de uma requisio Ajax. Utilizando uma lgica de modificao do DOM como ficaria nosso teste?
Listagem 7. Testando com Ajax alterao de um elemento na
rvore DOM.
<script type=text/javascript>
function callback(data) {
$(#contentAjax).html(data);
}
Screw.Unit(function() {
describe(Faz um requisicao Ajax e retorna um html como sucesso,
function() {
it(mockando e preenchendo div com conteudo do ajax,
function() {
var html = <span>Camiseta Vermelha</span>
expect($(#contentAjax).html()).to(equal, );
Smoke.Ajax.mock(/produto/camiseta, html, 200);
$.ajax( {
url : /produto/camiseta,
success : callback
});
wait(function() {
expect($(#contentAjax).html())
.to(equal, html);
}, 50);
});
});
});
</script>

Na Listagem 7 simulamos uma requisio que quando efetuada com


sucesso deve nos retornar um HTML que vai ser tratado por uma funo criada por nos chamada callback que recebe como argumento data
que nada mais que a resposta da requisio em texto. No exemplo acima verificamos se uma parte da rvore DOM dos nossos componentes
foram alterados de acordo com o que espervamos. Ainda utilizando o
exemplo da Listagem 7 podemos testar de outra maneira a alterao na
rvore DOM usando apenas a funo callback sem precisar simular a
requisio Ajax, como mostrado na Listagem 8.
Listagem 8. Testando callback h alterao de um elemento
na rvore DOM.
<script type=text/javascript>
Screw.Unit(function() {
describe(Preenche na div um html, function() {
it(testando callback de um ajax, function() {
$(#contentAjax).html();
var html = <span>Camiseta Amarela</span>;
callback(html);
expect($(#contentAjax).html()).to(equal, html);
});
});
});
</script>

Verificar que um elemento foi alterado e que seu Ajax est seguindo
o fluxo dos mtodos de callback de sucesso e de erro importante.
Conseguimos testar nosso cdigo Javascript, independentemente
de chamadas ao server side. Focamos apenas no que realmente interessa, no client side da aplicao, no que feito quando obtemos
o resultado.

Consideraes finais
Como foi visto, muitas vezes no damos a devida importncia aos cdigos que fazemos no client side da aplicao. Valorizamos na maioria
das vezes o lado server side e podemos terminar com dados inconsistentes em nosso HTML ou mesmo efetuarmos clculos invlidos que
podem afetar tambm os resultados no servidor. Testes de unidade e
abordagens como Test-Driven-Development so fceis de serem aplicadas utilizando as ferramentas QUnit, ScrewUnit e Smoke

Referncias
Screw Unit
http://github.com/rsutphin/screw-unit/
Smoke
http://github.com/drogus/smoke/
QUnit
http://docs.jquery.com/QUnit
Blog da Caelum
http://blog.caelum.com.br/2010/07/15/arredondamento-no-java-do-double-aobigdecimal
Blog do Luca Grulla
http://www.lucagrulla.it/blog/2010/06/15/javascript-testing/
How to test your JavaScript code with QUnit
http://net.tutsplus.com/tutorials/javascript-ajax/how-to-test-your-javascript-codewith-qunit/
Fault-tolerant system
http://en.wikipedia.org/wiki/Fault-tolerant_system
Unobtrusive JavaScript
http://en.wikipedia.org/wiki/Unobtrusive_JavaScript

49

Você também pode gostar