44 javascript

Upload: vagner-almeida

Post on 09-Jan-2016

17 views

Category:

Documents


0 download

DESCRIPTION

Java

TRANSCRIPT

  • 46

    : : www.mundoj.com.br : :

    Testando seus cdigos JavaScript: A importncia e a

    facilidade de cri-los

    Lucas Souza

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

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

    Aprenda como escrever testes de unidade para o lado

    cliente da sua aplicao

    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 pro-blemas 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 r-vore DOM, cdigo de chamadas Ajax para o servidor. Quando

    precisamos alterar estes cdigos temos uma dificuldade imensa.

    Em relao a nossa aplicao, a primeira opo prioriza a fun-

    cionalidade, 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 usabi-

    lidade.

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

    o contnua. Com isso, obtemos cdigos mais legveis e coesos e,

    evidentemente, com menor nmero de bugs.

  • 47

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

    tornar a pgina preenchida com o valor. Um cdigo JavaScript que calcula o valor do imposto, sem ne-

    nhuma requisio feita no server side.

    Pensando em cada vez mais melhorar a usuabilidade e a experi-ncia do usurio em relao a nossa aplicao, ou seja, pensando na questo do graceful degradation, a primeira opo mais re-comendada. 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 Test-Driven Development, que uma excelente prtica de desenvol-vimento, 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 colocar a funo on-load. 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 so includos alguns elementos HTML onde o QUnit exibir os resul-tados 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 adminis-trativa. 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.

    Listagem 2. Criao do clculo de impostos.

    window.onload = function() {

    test(calcula imposto corretamente, function() {

    equals(5.7, Imposto.calcula(10.20, 0.5, 0.6));

    });

    }

    QUnit example

    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 lingua-gens de programao, por exemplo, a linguagem Java. A lingua-gem 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 so-luo 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 : :

    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.

    Listagem 4. Clculo 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);}

    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, Parabens!, 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, Parabens!);

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

    }, 50);

    });

    });

    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.

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

    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 como alguma men-sagem 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.

  • 49

    Listagem 6. Testando o caso de erro.

    Listagem 8. Testando callback h alterao de um elemento na rvore DOM.

    Listagem 7. Testando com Ajax alterao de um elemento na rvore DOM.

    it(mockando uma requisicao ajax com erro, function() {

    var resultado, httpStatus;

    Smoke.Ajax.mock(/produto, Oops, 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, Oops);

    expect(httpStatus).to(equal, 500);

    }, 50);

    });

    Screw.Unit(function() { describe(Preenche na div um html, function() { it(testando callback de um ajax, function() { $(#contentAjax).html(); var html = Camiseta Amarela; callback(html); expect($(#contentAjax).html()).to(equal, html); }); });});

    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 = Camiseta Vermelha

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

    });

    });

    });

    No exemplo acima, definimos dentro do mtodo wait, que ele deve retornar na varivel resultado um valor igual a "Oops" 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 possibili-dade que o Smoke junto ao Screw.Unit nos oferece para usar um mock de uma requisio Ajax. Utilizando uma lgica de modifica-o do DOM como ficaria nosso teste?

    Na Listagem 7 simulamos uma requisio 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 requisio em texto. No exemplo aci-ma 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.

    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 in-teressa, 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 c-digos que fazemos no client side da aplicao. Valorizamos na maioria das vezes o lado server side e podemos terminar com dados inconsis-tentes 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 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

    Referncias