Rodando seus testes com Frisby.js em um ambiente de CI - Parte 1: Introdução ao Grunt

O post de hoje faz parte do #desafioAgileTesters. O Galani (@avontz) me desafiou a escrever um post sobre Frisby.js avançado e aqui estou eu! :)

O objetivo deste post é mostrar como colocar seu projeto de testes com Frisby.js para rodar em um ambiente de Integração Contínua, usando Jenkins e Grunt. Por motivos didáticos, como temos muita coisa para falar, optei por dividir em duas partes em vez de criar um post gigante e que seja cansativo de ler.

Nessa primeira parte, vamos fazer uma introdução ao Grunt e usá-lo para rodar nossos testes com Frisby.js.

IMPORTANTE

Este post presume que você tenha lido o post "Testando suas APIs com Frisby.js", escrito pelo Leonardo Galani em seu blog Keep Testing.


Um pouco sobre o Grunt

O Grunt é uma ferramenta de automação de tarefas escrita em JavaScript e que roda na plataforma Node.js. Você provavelmente já ouvir falar de ferramentas para automação de build e de tarefas em outras linguagens, como o Maven, Ant, Gradle (que já foi assunto de posts do blog, relembre aqui), Rake, Make, dentre outras. No mundo JavaScript, temos o Grunt para esse intuito. :)


Como instalar?

No post do Galani, vimos a instalação do Frisby.js e do Jasmine-node, correto? Para instalar o Grunt, precisamos digitar no Terminal o seguinte:

npm install -g grunt-cli

Perceba que estamos instalando grunt-cli em vez de grunt. Por que? A função do grunt-cli é executar qualquer versão do Grunt, com isso, podemos ter versões diferentes do Grunt em cada projeto, permitindo rodar na nossa máquina sem maiores problemas.

Agora, vamos ver como usar o Grunt em um projeto. No post sobre Frisby.js, você deve ter definido um diretório para seu projeto e criado um arquivo chamado package.json na raiz desse diretório. Esse arquivo, até então, deve estar parecido com:

{
"name": "exemplo-grunt",
"version": "0.0.1",
"dependencies": {
    "frisby": "latest",
    "jasmine-node": "latest"
    }
}

Para instalar uma versão do Grunt especificamente no nosso projeto, navegue até o diretório do projeto e digite o comando:

npm install grunt --save-dev

Após a execução do comando, você verá que, no arquivo package.json, foi incluída automaticamente a dependência do grunt:

{
"name": "exemplo-grunt",
"version": "0.0.1",
"dependencies": {
    "frisby": "latest",
    "jasmine-node": "latest"
    },
"devDependencies": {
    "grunt": "^0.4.5"
    }
}

Qual é o nosso objetivo? Queremos usar o Grunt para automatizar a execução dos nossos testes do Frisby.js, que rodam com o Jasmine-node. Para fazermos isso, vamos usar um plugin chamado grunt-jasmine-node (o nome já diz tudo, não?). Instalar o plugin no nosso projeto é muito simples, basta usarmos o mesmo comando anterior:

npm install grunt-jasmine-node --save-dev

Se tudo der certo, você verá uma nova dependência no package.json:

{
"name": "exemplo-grunt",
"version": "0.0.1",
"dependencies": {
    "frisby": "latest",
    "jasmine-node": "latest"
    },
"devDependencies": {
    "grunt": "^0.4.5",
    "grunt-jasmine-node": "^0.2.1"
    }
}

Um aspecto excelente do Grunt é o grande número de plugins disponíveis (quase 4000!), que estão listados no próprio site da ferramenta. Sempre que quiser automatizar algo com o Grunt, verifique na lista de plugins se já existe algum que faça o que você precisa.


Como o Grunt funciona?

O Grunt roda em cima de um arquivo chamado Gruntfile.js, que descreve as tarefas a serem executadas para o build do projeto. O arquivo deve ficar na raiz do projeto (da mesma forma que o package.json). A estrutura básica de um Gruntfile é a seguinte:

module.exports = function(grunt) {  
  grunt.initConfig({
     // configurações das tasks
  });
  // carrega plugins
  grunt.loadNpmTasks('nome-do-plugin');
};

No nosso caso, vamos usar apenas 1 plugin, o grunt-jasmine-node. Na página do GitHub do plugin, já nos é mostrado exatamente o que precisamos colocar no Gruntfile. O arquivo ficará assim:

module.exports = function(grunt) {  
  grunt.initConfig({
    jasmine_node: {
      options: {
        forceExit: true,
        match: '.',
        matchall: false,
        extensions: 'js',
        specNameMatcher: 'spec',
        jUnit: {
          report: true,
          savePath : "./build/reports/jasmine/",
          useDotNotation: true,
          consolidate: true
        }
      },
      all: ['spec/']
    }
  });

  grunt.loadNpmTasks('grunt-jasmine-node');

  grunt.registerTask('default', ['jasmine_node']);
};

Podemos ver que, dentro de initConfig(), criamos uma task chamada jasmine_node, que contém as configurações do Jasmine para o projeto, como o path para salvar reports, extensão dos arquivos, diretório onde buscar scripts, etc.. Repare que, no final da task, onde se lê all: ['spec/'], é o diretório onde o Jasmine vai procurar por nossos scripts de teste. Caso os testes não estejam em um diretório spec, você deve alterar essa linha no Gruntfile, informando o diretório correto.

O final do arquivo é bem explicativo: primeiro estamos carregando o plugin do grunt-jasmine-node e, em seguida, dizemos ao Grunt que a task default (padrão) deverá rodar a task jasmine-node.


Rodando o Grunt

Para rodar o build do nosso projeto, verifique se você está no diretório do projeto e digite no Terminal o seguinte comando complexo parametrizado:

grunt

Se tudo correr bem, você verá no console algo como:

grunt exec


Projeto de exemplo

Criei, no meu GitHub, um projeto de exemplo contendo tudo que aprendemos nesse post. Nesse projeto, adicionei um outro plugin ao Gruntfile, o grunt-contrib-jshint. Esse plugin valida a sintaxe dos scripts e é extremamente recomendado utilizá-lo. Vejam no projeto como ficou o Gruntfile. :)

Na parte 2 do post, vamos mostrar como colocar esse projeto de exemplo em um job no Jenkins e dar umas dicas sobre Frisby.js.

Não deixem de dar uma olhada nas referências! Até a parte 2! :D


Referências

http://blog.caelum.com.br/automacao-de-build-de-front-end-com-grunt-js/
http://tableless.com.br/grunt-voce-deveria-estar-usando/
http://zenorocha.com/automatizando-tarefas-js-com-grunt/
http://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies
http://stackoverflow.com/questions/22343224/difference-between-tilde-and-caret-in-package-json
https://github.com/jasmine-contrib/grunt-jasmine-node"
https://github.com/gruntjs/grunt-contrib-jshint"

Livro introdutório sobre Grunt: http://www.amazon.com/Getting-Started-Grunt-JavaScript-Runner/dp/1783980621


Sobre o autor: Stefan Teixeira trabalha como QA Engineer e, desde o final de 2014, tem se aventurado no mundo DevOps. É Bacharel em Ciência da Computação pela UFRJ e MBA em Garantia de Qualidade de Software pela Escola Politécnica da UFRJ. Entusiasta de Testes Automatizados (e de tudo que possa ser automatizado!), Agile Testing e da cultura DevOps.

Contatos: stefanfk@gmail.com | Twitter | LinkedIn


comments powered by Disqus