Front End

27 mai, 2015

Brincando com Jasmine

Publicidade

brincando-jasmine

Você testa seu código Javascript? Se a resposta foi não, nunca é tarde pra começar. Não vou me alongar aqui falando o por que tanta gente fala de fazer testes (existem milhares de artigos a respeito). Vou direto ao assunto: Jasmine.

O tal do Jasmine

Jasmine é um framework behavior-driven development para testar nossos nossas habilidades em Javascript. Uma das coisas legais que particularmente achei dele é que a sintaxe é bem intuitiva, o que faz com que escrever testes se torne uma tarefa fácil.

Mostrar na prática é bem melhor que só na teoria, então, vamos lá! Primeiro faça o download da última versão do Jasmine (recomendo seguir o passo a passo deles no GitHub, que é super tranquilo).

Pra essa brincadeira, criei duas pastas: uma com o nome jasmine onde joguei todos os arquivos do framework e outra chamada hello, onde vamos jogar os arquivos desse primeiro exemplo rápido. Dentro dessa pasta vamos criar uma pasta chamada spec, onde deixaremos os arquivos relacionados aos testes. Nossa pasta hello seria assim:

  • hello.js => nossa mágica;
  • spec/index.html => para podermos visualizar o resultado dos nossos testes;
  • spec/hello.spec.js => nossos testes.

E a estrutura completa ficaria assim:

├── jasmine (todos os arquivos do framework)
└── hello
    ├── hello.js
    └── spec
        ├── index.html
        └── hello.spec.js

Um adendo: essa foi uma organização só a fim de exemplo.

Então temos nosso menino spec/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Jasmine</title>
  <link rel="shortcut icon" type="image/png" href="../../jasmine/lib/jasmine-2.0.0/jasmine_favicon.png">
  <link rel="stylesheet" type="text/css" href="../../jasmine/lib/jasmine-2.0.0/jasmine.css">

  <script type="text/javascript" src="../../jasmine/lib/jasmine-2.0.0/jasmine.js"></script>
  <script type="text/javascript" src="../../jasmine/lib/jasmine-2.0.0/jasmine-html.js"></script>
  <script type="text/javascript" src="../../jasmine/lib/jasmine-2.0.0/boot.js"></script>

  <script src="../hello.js"></script>
  <script src="hello.spec.js"></script>
</head>
<body>
</body>
</html>

Aí temos um exemplo simples de arquivo Javascript:

ar Hello = function() {};

Hello.prototype.sayHi = function(name) {
  return 'my name is ' + name + ' and I\'m learning Jasmine!';
};

Observando o arquivo anterior, conseguimos já visualizar o que acontece. Mentalmente já esperamos que ao criarmos um objeto utilizando Hello e chamarmos o método sayHy, deve-se retornar uma string específica com o argumento que passarmos.

Passando para a parte testável da coisa, poderíamos implementar nosso teste assim:

describe('Hello :)', function() {

  var hello = new Hello();

  it('says my name', function() {
    expect(hello.sayHi('Fabeni')).toEqual('my name is Fabeni and I\'m learning Jasmine!');
  });

});

Destrinchando nosso arquivo de teste:

  • describe => é o que chamamos de suite. Seu nome, no caso Hello, geralmente define um componente da sua aplicação (pode ser uma classe, uma função ou qualquer outra coisa). Aceita 2 argumentos: uma string que é o nome da suite e uma função que é o bloco de código que implementamos o teste.
  • it() => resumidamente, é uma função que diz o que um pequeno pedaço do seu componente deve fazer. No exemplo, demos uma descrição do teste (says my name), e esperamos (a analogia com o expect) que o métodosayHi, quando chamado com o argumento Fabeni, retorne uma determinada string (my name is Fabeni and I’m learning Jasmine!).

Poderíamos também mudar algumas coisas na organização do código e adicionarmos a função beforeEach:

describe('Hello :)', function() {

  var hello;

  beforeEach(function() {
    hello = new Hello();
  });

  it('says my name', function() {
    expect(hello.sayHi('Fabeni')).toEqual('my name is Fabeni and I\'m learning Jasmine!');
  });

});

A função beforeEach, como o próprio nome diz, roda uma vez antes de cada spec do describe. Também existe oafterEach, que tem o papel inverso e roda uma vez depois de cada spec.

Se abrirmos nosso index.html para rodarmos nossos testes, teremos algo assim:

Nosso teste passou!
Nosso teste passou!

É possível também usar o Jasmine para fazer testes em aplicações com Node.js através do Jasmine Node. Depois de instalado, precisaríamos fazer pequenos ajustes no nosso código para testá-lo:

Nosso arquivo hello.js ficaria assim:

var Hello = function() {};

Hello.prototype.sayHi = function(name) {
  return 'my name is ' + name + ' and I\'m learning Jasmine!';
};

module.exports = Hello;

E nosso arquivo de testes hello.spec.js ficaria assim:

var Hello =  require('./hello.js');

describe('Hello', function() {

  var hello = new Hello();

  it('says my name', function() {
    expect(hello.sayHi('Fabeni')).toEqual('my name is Fabeni and I\'m learning Jasmine!');
  });

});

E aí é só rodarmos nosso teste via terminal:

jasmine-node-hello

Testes antes?

No exemplo anterior primeiro desenvolvemos nosso código e depois escrevemos nosso teste. No TDD ocorre o inverso: primeiro escreveríamos os testes e depois o nosso código. Achou estranho? Vamos tentar brincar.

Comecemos de algo básico: imagine que queremos ter uma função simples que aceita 2 números como argumentos e nos retorna o resultado da adição de ambos. Poderíamos fazer um teste simples assim:

describe('Calc', function() {

  it('should calculate the addition of two numbers', function() {
    expect(add(5,3)).toEqual(8);
  });

  it('1 argument - should calculate the addition using the argument twice', function() {
    expect(add(5)).toEqual(10);
  });

});

No teste acima, quebramos nosso componente em 2 testes específicos:

  • Primeiro esperamos que ao passarmos os números 5 e 3, ele nos retorne 8, fazendo a soma normalmente.
  • Segundo, esperamos que se apenas um argumento for passado, esse argumento seja somado a ele mesmo, ou seja, se apenas o número 5 for passado, o resultado deve ser 10, vindo da operação 5 + 5.

Obs.: Poderíamos ter mais um monte de testes, como verificar se o argumento passado é realmente um número, mas deixemos apenas esses 2 para o exemplo.

Tendo isso em mente, podemos partir pro nosso código:

function add(x, y) {
  return x + y;
}

Com certeza, de cara já poderíamos imaginar algo assim certo? No entanto, como é de se esperar, isso vai nos retornar um erro quando rodarmos os testes.

jasmine-erro

Nossos testes quebraram e conseguimos ver exatamente onde: Calc 1 argument – should calculate the addition using the argument twice. Isso acontece pois não fizemos nenhum tratamento na nossa função, caso recebêssemos apenas um argumento. Vamos lá então:

function add(x, y) {
  y ? return x + y; : return x + x;
}

Agora, se rodarmos os testes novamente:

jasmine-ok-2

Acho que é isso! No próximo artigo vou tentar escrever um pouco sobre os matchers do Jasmine, que é uma outra parte bem legal do framework. Deixo aqui meu obrigado ao Weslley Araujo pela revisão do conteúdo!

Gostou? Escrevi alguma groselha? Quer melhorar? Abra uma issue com a hashtag 1postperweek e vamos conversar.

***

Artigo publicado originalmente em: http://www.raphaelfabeni.com.br/brincando-com-jasmine/