lucas souza testando seus códigos javascript: a ... · entusiasta de metodologias ... basta...

4
46 : : www.mundoj.com.br : : Testando seus códigos JavaScript: A importância e a facilidade de criá-los Lucas Souza ([email protected]): é 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. Caíres Vinicius ([email protected]): é desenvolvedor e consultor pela Caelum nas linguagens em Java, Ruby e Javascript. Entusiasta de usabilidade para Web e Javascript Server-side. 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. Aprenda como escrever testes de unidade para o lado cliente da sua aplicação ódigo JavaScript tem se tornado cada vez mais frequente em aplicações web ricas, as ditas aplicações web 2.0. Bibliotecas como jQuery, Prototype, Mootools e outras facilitam muito o trabalho dos desenvolvedores. Porém o código muitas vezes acaba não recebendo a atenção necessária, e os pro- blemas são descobertos ou pelos usuários das aplicações ou pelos desenvolvedores quando utilizam ferramentas de debugging no estilo do Firebug. Mesmo com essas ferramentas e com a correção de erros sendo feita frequentemente, não temos muito cuidado no processo de isolar determinados códigos assim como é feito quando nos referimos a códigos no server side. O código termina como uma big ball of mud, ou uma grande “bola de lama”, onde misturamos códigos que manipulam a ár- vore DOM, código de chamadas Ajax para o servidor. Quando precisamos alterar estes códigos temos uma dificuldade imensa. Em relação a nossa aplicação, a primeira opção prioriza a fun- cionalidade, isto é, deve funcionar com ou sem javascript. Essa solução é conhecida como Graceful Degradation. Garantir que a aplicação funcione sem javascript vai gerar uma perda de usabi- lidade. O objetivo do artigo é mostrar que testes em códigos JavaScript são fáceis de fazer e hoje em dia existem muitas ferramentas que nos auxiliam em processos complexos, como a criação de mocks e stubs, além da integração destes testes com servidores de integra- ção contínua. Com isso, obtemos códigos mais legíveis e coesos e, evidentemente, com menor número de bugs.

Upload: vanthu

Post on 16-May-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

46

: : www.mundoj.com.br : :

Testando seus códigos JavaScript: A importância e a

facilidade de criá-los

Lucas Souza

([email protected]): é 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.

Caíres Vinicius

([email protected]): é desenvolvedor e consultor pela Caelum nas linguagens em Java, Ruby e Javascript. Entusiasta de usabilidade para Web e Javascript Server-side.

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.

Aprenda como escrever testes de unidade para o lado

cliente da sua aplicação

ódigo JavaScript tem se tornado cada vez mais frequente em aplicações web ricas, as ditas aplicações web 2.0. Bibliotecas como jQuery, Prototype, Mootools e outras

facilitam muito o trabalho dos desenvolvedores. Porém o código muitas vezes acaba não recebendo a atenção necessária, e os pro-blemas são descobertos ou pelos usuários das aplicações ou pelos desenvolvedores quando utilizam ferramentas de debugging no estilo do Firebug. Mesmo com essas ferramentas e com a correção de erros sendo feita frequentemente, não temos muito cuidado no processo de isolar determinados códigos assim como é feito quando nos referimos a códigos no server side.

O código termina como uma big ball of mud, ou uma grande “bola de lama”, onde misturamos códigos que manipulam a ár-vore DOM, código de chamadas Ajax para o servidor. Quando

precisamos alterar estes códigos temos uma dificuldade imensa.

Em relação a nossa aplicação, a primeira opção prioriza a fun-

cionalidade, isto é, deve funcionar com ou sem javascript. Essa

solução é conhecida como Graceful Degradation. Garantir que a

aplicação funcione sem javascript vai gerar uma perda de usabi-

lidade.

O objetivo do artigo é mostrar que testes em códigos JavaScript

são fáceis de fazer e hoje em dia existem muitas ferramentas que

nos auxiliam em processos complexos, como a criação de mocks e

stubs, além da integração destes testes com servidores de integra-

ção contínua. Com isso, obtemos códigos mais legíveis e coesos e,

evidentemente, com menor número de bugs.

47

Testes de unidade com QUnit

Vamos primeiro simular um cenário no qual devemos calcular alguns impostos e mostrar o resultado para o usuário. Poderíamos resolver o problema de duas maneiras:•Uma requisição no server side para calcular nosso imposto e re-

tornar a página preenchida com o valor. •Um código JavaScript que calcula o valor do imposto, sem ne-

nhuma requisição feita no server side.

Pensando em cada vez mais melhorar a usuabilidade e a experi-ência do usuário em relação a nossa aplicação, ou seja, pensando 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.

Neste caso, fazendo o cálculo através de um código JavaScript deixaria a aplicação mais rápida pelo fato de não ter que fazer uma requisição e esperar a resposta do servidor, evitando também tráfegos desnecessários pela rede.

Quando não testamos, perdemos qualidade. Com JavaScript não é diferente, e se não testarmos, podemos colocar um valor errado que pode prejudicar a parte financeira que utiliza sua aplicação 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-Driven Development, que é uma excelente prática de desenvol-vimento, e que já é seguida fortemente quando testamos códigos server side. Vamos começar pela criação de um teste e depois 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 Java. O QUnit é a ferramenta escolhida pelo conhecido projeto JQuery para efetuar os testes da sua implementação e também dos plugins existentes para ele. Mas também pode ser utilizado para testar códigos JavaScript que não utilizam JQuery, exatamente o 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 para fazer a formatação do HTML retornado. Na tag <body> são incluídos alguns elementos HTML onde o QUnit exibirá os resul-tados dos nossos testes.

Nosso teste falha porque ainda não implementamos a função "calcula". Para calcular o valor com os impostos precisamos de três informações: valor, valor do imposto e uma taxa adminis-trativa. No nosso caso, vamos fazer uma multiplicação e uma adição como fórmula para o cálculo do nosso imposto. Sabendo quais argumentos e qual a fórmula do cálculo do imposto, vamos implementar nossa função dentro do arquivo impostos.js, assim como feito na Listagem 2.

Listagem 1. Criação do teste utilizando Qunit.

Listagem 2. Criação do cálculo de impostos.

<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>

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

Se executarmos em nosso browser favorito, o código presente na Listagem 1, perceberemos que ele nos retorna uma mensagem de erro, dizendo que nosso código falhou. Isto ocorre por causa do arredondamento do ponto flutuante do Javascript. Ao invés de retornar 5.7, nossa função retorna o valor 5.699999999999999.

O que aconteceu no código acima é um problema que pode ser considerado crônico em relação a arredondamentos em lingua-gens de programação, por exemplo, a linguagem Java. A lingua-gem JavaScript também tem problemas com arredondamento de pontos flutuantes.

Percebemos este problema apenas porque nosso código Javascript recebeu a devida atenção e criamos um teste de unidade para um cálculo que parecia simples, mas que poderia causar grandes transtornos.

Mas como podemos resolver este problema? Existe alguma so-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

48

: : 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 utilizando a classe BigNumber é mostrado na Listagem 3.

Listagem 3. Cálculo de impostos utilizando BigNumber.

Listagem 4. Cálculo de impostos utilizando toFixed.

Listagem 5. Mock de Ajax com ScrewUnit e Smoke.

Imposto.calcula = function(valor, imposto, taxa) { var valorComImposto = new BigNumber(valor).multiply(imposto); return Number(new BigNumber(taxa).add(valorComImposto));}

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

<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;

}

});

wait(function(){

expect(resultado).to(equal, “<p>Parabens!</p>”);

expect(httpStatus).to(equal, “success”);

}, 50);

});

});

</script>

</head>

<body></body>

</html>

Utilizando a classe BigNumber e executando o teste novamente, ele passará.

Porém existe outra maneira de corrigir nossa função utilizando o método toFixed() do próprio Javascript, que formata um número usando a notação de um ponto fixo. Utilizando o toFixed nosso código ficaria como o descrito na Listagem 4.

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 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.

Como testaríamos nossa requisição Ajax? Como verificamos se o elemento HTML foi alterado? Fazendo uma requisição de verdade?

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 verificação se a mesma foi feita com sucesso, simulando seu método de callback de sucesso ou simulando uma requisição e um possível erro no server side execute o seu método de callback de erro.

Para os exemplos de testes de Ajax usaremos o Screw.Unit como bi-blioteca de testes e Smoke como biblioteca de Mock. O Screw.Unit e o Smoke são duas bibliotecas ativas e existem inúmeros forks dos projetos presentes no Github. Utilizaremos como exemplo os fork de rsutphin e drogus, respectivamente. Nosso primeiro exemplo (Listagem 5) mostrará a criação de uma requisição Ajax, que simula o retorno de um código HTTP 200, para indicar sucesso e também o retorno de um HTML com uma mensagem de sucesso dentro de uma tag <p>.

Um teste simples para verificar se a resposta que o server side nos enviou está correta quando o status da requisição é sucesso. Neste primeiro exemplo, testamos o caso de sucesso da requisição, mas e quando essa requisição não é feita com sucesso, o que deve acontecer?

Em nosso exemplo deve ser retornado um status 500 do HTTP e também um HTML dentro de uma tag <p> como alguma men-sagem de erro. Vamos simular este comportamento e testar se o retorno está correto. Basta adicionarmos mais um comportamento de teste, através da função it(). Esta nova verificação será feita na Listagem 6.

49

Listagem 6. Testando o caso de erro.

Listagem 8. Testando callback há alteração de um elemento na árvore DOM.

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

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);

});

<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>

<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>

No exemplo acima, definimos dentro do método wait, que ele 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.

O exemplo que utilizamos foi apenas para demonstrar a possibili-dade que o Smoke junto ao Screw.Unit nos oferece para usar um mock de uma requisição Ajax. Utilizando uma lógica de modifica-ção do DOM como ficaria nosso teste?

Na Listagem 7 simulamos uma requisição que quando efetuada com sucesso deve nos retornar um HTML que vai ser tratado por uma fun-ção criada por nos chamada callback que recebe como argumento data que nada mais é que a resposta da requisição em texto. No exemplo aci-ma verificamos se uma parte da árvore DOM dos nossos componentes foram alterados de acordo com o que esperávamos. Ainda utilizando o exemplo da Listagem 7 podemos testar de outra maneira a alteração na árvore DOM usando apenas a função callback sem precisar simular a requisição Ajax, como é mostrado na Listagem 8.

Verificar que um elemento foi alterado e que seu Ajax está seguindo o fluxo dos métodos de callback de sucesso e de erro é importante. Conseguimos testar nosso código Javascript, independentemente de chamadas ao server side. Focamos apenas no que realmente in-teressa, no client side da aplicação, no que é feito quando obtemos o resultado.

Considerações finais

Como foi visto, muitas vezes não damos a devida importância aos có-digos que fazemos no client side da aplicação. Valorizamos na maioria das vezes o lado server side e podemos terminar com dados inconsis-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-das utilizando as ferramentas QUnit, ScrewUnit e Smoke•

• 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-ao-

bigdecimal

• 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-code-

with-qunit/

• Fault-tolerant system

http://en.wikipedia.org/wiki/Fault-tolerant_system

• Unobtrusive JavaScript

http://en.wikipedia.org/wiki/Unobtrusive_JavaScript

Referências