Você está na página 1de 4

: : www.mundoj.com.

br : :

Caíres 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
Computação pela Universidade de Ribeirão Preto, possui a
certificação 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 códigos


JavaScript: A importância e a
facilidade de criá-los
Aprenda como escrever testes de unidade para o lado
cliente da sua aplicação
A linguagem JavaScript tem se tornado a principal
nas aplicações conhecidas como rich applications ou
aplicações web 2.0. Porém ainda não tem recebido a
devida atenção quando o assunto diz respeito a testes
automatizados. No artigo será mostrado na prática
a importância e a relevância de se criar testes para
seus códigos JavaScript, mostrando ferramentas que
permitem a criação de simples testes de unidade, até a
criação de mocks simulando dependências complexas.

ódigo JavaScript tem se tornado cada vez mais frequente precisamos alterar estes códigos temos uma dificuldade imensa.
em aplicações web ricas, as ditas aplicações web 2.0.
Bibliotecas como jQuery, Prototype, Mootools e outras Em relação a nossa aplicação, a primeira opção prioriza a fun-
facilitam muito o trabalho dos desenvolvedores. Porém o código cionalidade, isto é, deve funcionar com ou sem javascript. Essa
muitas vezes acaba não recebendo a atenção necessária, e os pro- solução é conhecida como Graceful Degradation. Garantir que a
blemas são descobertos ou pelos usuários das aplicações ou pelos aplicação funcione sem javascript vai gerar uma perda de usabi-
desenvolvedores quando utilizam ferramentas de debugging no lidade.
estilo do Firebug. Mesmo com essas ferramentas e com a correção
de erros sendo feita frequentemente, não temos muito cuidado O objetivo do artigo é mostrar que testes em códigos JavaScript
no processo de isolar determinados códigos assim como é feito são fáceis de fazer e hoje em dia existem muitas ferramentas que
quando nos referimos a códigos no server side. nos auxiliam em processos complexos, como a criação de mocks e
O código termina como uma big ball of mud, ou uma grande stubs, além da integração destes testes com servidores de integra-
“bola de lama”, onde misturamos códigos que manipulam a ár- ção contínua. Com isso, obtemos códigos mais legíveis e coesos e,
vore DOM, código de chamadas Ajax para o servidor. Quando evidentemente, com menor número de bugs.

46
Testes de unidade com QUnit Listagem 1. Criação do teste utilizando Qunit.
Vamos primeiro simular um cenário no qual devemos calcular <html>
alguns impostos e mostrar o resultado para o usuário. Poderíamos <head>
resolver o problema de duas maneiras: <link rel=”stylesheet” href=”qunit.css” type=”text/css” media=”screen” />
•Uma requisição no server side para calcular nosso imposto e re- <script type=”text/javascript” src=” qunit.js”></script>
tornar a página preenchida com o valor. <script type=”text/javascript” src=”impostos.js”></script>
•Um código JavaScript que calcula o valor do imposto, sem ne-
nhuma requisição feita no server side. <script>
window.onload = function() {
Pensando em cada vez mais melhorar a usuabilidade e a experi- test(“calcula imposto corretamente”, function() {
ência do usuário em relação a nossa aplicação, ou seja, pensando equals(5.7, Imposto.calcula(10.20, 0.5, 0.6));
na questão do graceful degradation, a primeira opção é mais re- });
comendada. Porém, é uma solução que possui um problema, que }
pode ser uma resposta lenta ao usuário. </script>

Neste caso, fazendo o cálculo através de um código JavaScript </head>


deixaria a aplicação mais rápida pelo fato de não ter que fazer <body>
uma requisição e esperar a resposta do servidor, evitando também <h1 id=”qunit-header”>QUnit example</h1>
tráfegos desnecessários pela rede. <h2 id=”qunit-banner”></h2>
<h2 id=”qunit-userAgent”></h2>
Quando não testamos, perdemos qualidade. Com JavaScript não
<ol id=”qunit-tests”></ol>
é diferente, e se não testarmos, podemos colocar um valor errado </body>
que pode prejudicar a parte financeira que utiliza sua aplicação </html>
ou não exibir um elemento HTML que deveria aparecer e não
aparece. O teste é também para garantir essa qualidade.

Em nosso primeiro código, adotaremos a abordagem de Test- Listagem 2. Criação do cálculo de impostos.
Driven Development, que é uma excelente prática de desenvol-
vimento, e que já é seguida fortemente quando testamos códigos Imposto.calcula = function(valor, imposto, taxa) {
server side. Vamos começar pela criação de um teste e depois return (valor * imposto) + taxa;
}
escreveremos o código javascript para que este teste passe.

Utilizaremos uma ferramenta de testes chamada QUnit, que é


muito semelhante ao JUnit utilizado para testes de unidade em Se executarmos em nosso browser favorito, o código presente na
Java. O QUnit é a ferramenta escolhida pelo conhecido projeto Listagem 1, perceberemos que ele nos retorna uma mensagem de
JQuery para efetuar os testes da sua implementação e também dos erro, dizendo que nosso código falhou. Isto ocorre por causa do
plugins existentes para ele. Mas também pode ser utilizado para arredondamento do ponto flutuante do Javascript. Ao invés de
testar códigos JavaScript que não utilizam JQuery, exatamente o retornar 5.7, nossa função retorna o valor 5.699999999999999.
que confere com o nosso cenário.

Para criarmos nosso teste utilizando o Qunit, basta escrever o


HTML da Listagem 1, e dentro da tag <script> colocar a função on-
load. Dentro da função onload, ficam as asserções que desejamos
efetuar. Um detalhe é que neste arquivo incluiremos o arquivo
impostos.js, que contém a função que desejamos testar. Também
está incluso a importação de um arquivo css do próprio QUnit O que aconteceu no código acima é um problema que pode ser
para fazer a formatação do HTML retornado. Na tag <body> são considerado crônico em relação a arredondamentos em lingua-
incluídos alguns elementos HTML onde o QUnit exibirá os resul- gens de programação, por exemplo, a linguagem Java. A lingua-
tados dos nossos testes. gem JavaScript também tem problemas com arredondamento de
pontos flutuantes.
Nosso teste falha porque ainda não implementamos a função
"calcula". Para calcular o valor com os impostos precisamos de Percebemos este problema apenas porque nosso código Javascript
três informações: valor, valor do imposto e uma taxa adminis- recebeu a devida atenção e criamos um teste de unidade para
trativa. No nosso caso, vamos fazer uma multiplicação e uma um cálculo que parecia simples, mas que poderia causar grandes
adição como fórmula para o cálculo do nosso imposto. Sabendo transtornos.
quais argumentos e qual a fórmula do cálculo do imposto, vamos
implementar nossa função dentro do arquivo impostos.js, assim Mas como podemos resolver este problema? Existe alguma so-
como feito na Listagem 2. lução 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 : :

precisão em cálculos com pontos flutuantes. Basta alterarmos a


implementação do código presente na função calcula. O código Listagem 5. Mock de Ajax com ScrewUnit e Smoke.
utilizando a classe BigNumber é mostrado na Listagem 3.
<html>
<head>
Listagem 3. Cálculo de impostos utilizando BigNumber. <script src=”jquery-1.3.2.js”></script>
<script src=”jquery.fn.js”></script>
Imposto.calcula = function(valor, imposto, taxa) { <script src=”jquery.print.js”></script>
var valorComImposto = new BigNumber(valor). <script src=”screw.builder.js”></script>
multiply(imposto); <script src=”screw.matchers.js”></script>
return Number(new BigNumber(taxa).add(valorComImposto)); <script src=”screw.events.js”></script>
} <script src=”screw.behaviors.js”></script>
<script src=”smoke.core.js”></script>
Utilizando a classe BigNumber e executando o teste novamente, <script src=”smoke.mock.js”></script>
ele passará. <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;
Porém existe outra maneira de corrigir nossa função utilizando o $.ajax({
método toFixed() do próprio Javascript, que formata um número url:”/meuRecurso”,
usando a notação de um ponto fixo. Utilizando o toFixed nosso success: function(data, textStatus){
código ficaria como o descrito na Listagem 4. resultado = data;
httpStatus = textStatus;
},
Listagem 4. Cálculo de impostos utilizando toFixed.
error: function(error){
Imposto.calcula = function(valor, imposto, taxa) { resultado = error.responseText;
return ((valor * imposto) + taxa).toFixed(2); httpStatus = error.status;
}
}
});

Testes de unidade com DOM, Ajax e Callbacks wait(function(){


utilizando Screw.Unit e Smoke expect(resultado).to(equal, “<p>Parabens!</p>”);
expect(httpStatus).to(equal, “success”);
Bibliotecas como jQuery nos ajudam a manipular a árvore DOM e }, 50);
principalmente a fazer requisições Ajax, que é a rotina mais comum });
para a grande maioria dos desenvolvedores, mas mesmo sendo });
muito corriqueira poucos testam e tomam o cuidado necessário.
</script>
Como testaríamos nossa requisição Ajax? Como verificamos se o </head>
elemento HTML foi alterado? Fazendo uma requisição de verdade? <body></body>
</html>
Para testes com Ajax temos a opção de criar objetos falsos, mais
conhecidos como mocks, que simulem a requisição e que façam a
Um teste simples para verificar se a resposta que o server side nos
verificação se a mesma foi feita com sucesso, simulando seu método
enviou está correta quando o status da requisição é sucesso. Neste
de callback de sucesso ou simulando uma requisição e um possível
primeiro exemplo, testamos o caso de sucesso da requisição, mas
erro no server side execute o seu método de callback de erro.
e quando essa requisição não é feita com sucesso, o que deve
Para os exemplos de testes de Ajax usaremos o Screw.Unit como bi- acontecer?
blioteca de testes e Smoke como biblioteca de Mock. O Screw.Unit
Em nosso exemplo deve ser retornado um status 500 do HTTP
e o Smoke são duas bibliotecas ativas e existem inúmeros forks dos
e também um HTML dentro de uma tag <p> como alguma men-
projetos presentes no Github. Utilizaremos como exemplo os fork
sagem de erro. Vamos simular este comportamento e testar se o
de rsutphin e drogus, respectivamente. Nosso primeiro exemplo
retorno está correto. Basta adicionarmos mais um comportamento
(Listagem 5) mostrará a criação de uma requisição Ajax, que simula
de teste, através da função it(). Esta nova verificação será feita na
o retorno de um código HTTP 200, para indicar sucesso e também
Listagem 6.
o retorno de um HTML com uma mensagem de sucesso dentro de
uma tag <p>.

48
Na Listagem 7 simulamos uma requisição que quando efetuada com
Listagem 6. Testando o caso de erro. sucesso deve nos retornar um HTML que vai ser tratado por uma fun-
ção criada por nos chamada callback que recebe como argumento data
it(“mockando uma requisicao ajax com erro”, function() {
que nada mais é que a resposta da requisição em texto. No exemplo aci-
var resultado, httpStatus;
ma verificamos se uma parte da árvore DOM dos nossos componentes
Smoke.Ajax.mock(“/produto”, “<p>Oops</p>”, 500);
$.ajax( {
foram alterados de acordo com o que esperávamos. Ainda utilizando o
url : “/produto”, exemplo da Listagem 7 podemos testar de outra maneira a alteração na
success : function(data, textStatus) { árvore DOM usando apenas a função callback sem precisar simular a
resultado = data; requisição Ajax, como é mostrado na Listagem 8.
httpStatus = textStatus;
},
error : function(error) {
Listagem 8. Testando callback há alteração de um elemento
resultado = error.responseText; na árvore DOM.
httpStatus = error.status;
<script type=”text/javascript”>
} Screw.Unit(function() {
}); describe(“Preenche na div um html”, function() {
it(“testando callback de um ajax”, function() {
wait(function() { $(“#contentAjax”).html(“”);
expect(resultado).to(equal, “<p>Oops</p>”); var html = “<span>Camiseta Amarela</span>”;
expect(httpStatus).to(equal, 500); callback(html);
}, 50); expect($(“#contentAjax”).html()).to(equal, html);
}); });
});
});
No exemplo acima, definimos dentro do método wait, que ele </script>
deve retornar na variável resultado um valor igual a "<p>Oops</
p>" e dentro da variável httpStatus, um código igual a 500. Apenas
simulamos o comportamento da requisição Ajax usando um mock. Verificar que um elemento foi alterado e que seu Ajax está seguindo
O exemplo que utilizamos foi apenas para demonstrar a possibili- o fluxo dos métodos de callback de sucesso e de erro é importante.
dade que o Smoke junto ao Screw.Unit nos oferece para usar um Conseguimos testar nosso código Javascript, independentemente
mock de uma requisição Ajax. Utilizando uma lógica de modifica- de chamadas ao server side. Focamos apenas no que realmente in-
ção do DOM como ficaria nosso teste? teressa, no client side da aplicação, no que é feito quando obtemos
o resultado.

Listagem 7. Testando com Ajax alteração de um elemento na


Considerações finais
árvore DOM. Como foi visto, muitas vezes não damos a devida importância aos có-
<script type=”text/javascript”>
digos que fazemos no client side da aplicação. Valorizamos na maioria
function callback(data) {
das vezes o lado server side e podemos terminar com dados inconsis-
$(“#contentAjax”).html(data); tentes em nosso HTML ou mesmo efetuarmos cálculos inválidos que
} podem afetar também os resultados no servidor. Testes de unidade e
abordagens como Test-Driven-Development são fáceis de serem aplica-
Screw.Unit(function() { das utilizando as ferramentas QUnit, ScrewUnit e Smoke•
describe(“Faz um requisicao Ajax e retorna um html como sucesso”,
function() {
it(“mockando e preenchendo div com conteudo do ajax”,
function() { Referências
var html = “<span>Camiseta Vermelha</span>” • Screw Unit
expect($(“#contentAjax”).html()).to(equal, “”); http://github.com/rsutphin/screw-unit/
Smoke.Ajax.mock(“/produto/camiseta”, html, 200); • Smoke
http://github.com/drogus/smoke/
$.ajax( { • QUnit
url : “/produto/camiseta”, http://docs.jquery.com/QUnit
success : callback • Blog da Caelum
}); http://blog.caelum.com.br/2010/07/15/arredondamento-no-java-do-double-ao-
bigdecimal
wait(function() { • Blog do Luca Grulla
expect($(“#contentAjax”).html()) http://www.lucagrulla.it/blog/2010/06/15/javascript-testing/
.to(equal, html); • How to test your JavaScript code with QUnit
http://net.tutsplus.com/tutorials/javascript-ajax/how-to-test-your-javascript-code-
}, 50); with-qunit/
}); • Fault-tolerant system
}); http://en.wikipedia.org/wiki/Fault-tolerant_system
}); • Unobtrusive JavaScript
http://en.wikipedia.org/wiki/Unobtrusive_JavaScript
</script>

49

Você também pode gostar