Não faça testes, faça specs!
![Não faça testes, faça specs!](https://www.bennadel.com/resources/uploads/2013/feelings_about_angularjs_over_time.png)
Como foi difícil escrever este artigo, ou melhor, esta série que iremos lançar. Eu sou desenvolvedor Java, demorei anos para entender todo parte do ecossistema que envolve a plataforma, o que cada framework faz, como é sua arquitetura, onde e como deveria ser usado e como googlar determinado problema. Lembro até hoje a alegria que tive ao configurar um projeto Struts + JPA usando Maven (até que enfim tinha entendido esse tal de gerenciador de dependências).
Enfim, você não sabe o quanto eu caminhei para chegar até aqui, para simplesmente ....... ter que reaprender tudo de novo!!! É isso mesmo amigos, bem-vindo ao maravilhoso reino encantando do JavaScript.
Curto e grosso amigo desenvolvedor: você tem um monte de nomes para aprender desse novo mundo, muitos nomes (node, npm, gulp, grunt, jasmine, typescript, react, webpack, babel, expressjs, bower, ...). É o tal do mundo front-end! E pode ter certeza que amanhã haverá mais frameworks / bibliotecas.
Para essa série, chamei Tiago Lage para ser coautor, que já estava nesse mundo antes de ser modinha e tentava, sem sucesso (por culpa minha), explicar-me features legais do javascript como hoisting.
Depois de um tempo batalhando lado a lado com frameworks para desenvolver algo minimamente decente, descobri que o mais importante disso tudo não é o que está no meu src/main/java, mas sim o que está no src/test/java. O seu código está ruim? Tem testes? Ok, depois alguém refatora. Mas não deixe de fazer testes!!! Aliás, a não ser que você trabalhe no StackOverflow e tenha usuários working for free legais que forneçam feedback exclusivo!
E como lidar com testes especificações em JavaScript? Bom, durante a série de artigos iremos testar diferentes códigos javascript e frameworks (jQuery, Vue, Angular), obtendo cobertura de código, usando mocks em funções e até mesmo no html. Vamos ver até onde isso vai....
Entendendo as especificações
Imagine por um momento que você está trabalhando em um projeto que teve a especificação perfeita, ou seja, todos os comportamentos esperados do sistema estão detalhadamente descritos, cada regra de negócio, cada input válido ou inválido, cada tela e mensagem de erro. Imaginou? Agora imagine que o computador possa entender essa especificação "perfeita". Poderíamos dizer então que se o computador pudesse validar todas estas especificações, então nosso sistema está correto, não é mesmo?
Essa modinha tendência começou a se difundir com o Ruby e o framework RSpec que prometia trazer o Behaviour Driven Development (Desenvolvimento Guiado por Comportamento) para o Ruby.
Entretanto, como todos sabem, os requisitos nunca são perfeitos e também não são escritos em uma linguagem de máquina. Portanto, o que podemos fazer para que essa estratégia funcione? Bom, podemos pegar os requisitos "reais" (descritos em um documento em linguagem de negócios), aperfeiçoá-los e traduzí-los para uma linguagem de máquina. A boa notícia é que grande parte do ferramental já existe na maioria das linguagens.
Bom, mas o que se ganho com toda essa trabalheira? Ela irá permitir utilizar Test Driven Development - TDD (Desenvolvimento guiado por testes). Desse modo, nosso projeto real começa com todos os testes falhando, à medida que desenvolvemos suas funcionalidades, os testes começam a passar. Assim, quando todos os testes estiverem passando, dizemos que nosso projeto está completo.
![Banner da Escola de Inovação e Gestão: Matricula-se na escola de Inovação e Gestão. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!](assets/alura-matricula-maior-escola-tecnologia-brasil-mais-500-mil-estudantes/matricula-escola-inovacao-gestao-alura-saiba-mais-versao-mobile.png)
First things first
A primeira atitude que precisamos tomar para começar a fazer testes em JavaScript é escolher um Framework. O mundo Java se divide em Team JUnit e Team TestNG. Há uma boa comparação aqui. No mundo JavaScript, a briga maior é entre o Team Jasmine e o Team Mocha.js (boa comparação aqui também). Desconsiderando as diferenças óbvias de linguagem, há também uma grande diferença conceitual na forma de abordagem dos testes entre o pessoal do Java e o pessoal do JavaScript. No mundo Java, em geral, os frameworks de testes seguem mais a filosofia do teste unitário de unidade, e no mundo JavaScript é mais comum a terminologia do Behavior Driven Design (BDD).
Segue exemplo de teste em Java (JUnit4). Veja que utilizamos anotações sobre os métodos para definir qual a função dos mesmos no ciclo de vida do nosso teste:
Suite de testes - AllTests:
https://github.com/tiagolpadua/MinhaCalculadoraJava
import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class) @SuiteClasses({ CalculadoraTest.class }) public class AllTests { }
Casos de teste - CalculadoraTest:
import static org.junit.Assert.assertEquals; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test;
public class CalculadoraTest {
@BeforeClass public static void runOnceBeforeClass() { System.out.println("@BeforeClass- executa uma vez antes de todos testes"); }
@AfterClass public static void runOnceAfterClass() { System.out.println("@AfterClass - executa uma vez após todos testes"); }
@Before public void runBeforeTestMethod() { System.out.println("@Before - executa antes de cada teste"); }
@After public void runAfterTestMethod() { System.out.println("@After - executa após cada teste"); }
@Test public void testSoma() { Calculadora calculadora = new Calculadora(); assertEquals(3, calculadora.somar(2, 1)); System.out.println("@Test - testSoma"); }
@Test public void testIncremento() { System.out.println("@Test - testIncremento"); Calculadora calculadora = new Calculadora(); assertEquals(3, calculadora.incrementar(2)); } }
Bom, mas isso aí talvez você já saiba de cor e salteado, mas e como é no mundo JavaScript?
O JavaScript não tem o recurso de anotações como o Java, nesse caso, segue o exemplo abaixo em JavaScript utilizando o framework Jasmine, que disponibiliza algumas funções para controlar o ciclo de vida dos testes e asserções sobre os resultados:
describe('Calculadora', function () {
beforeAll(function () { console.log('beforeAll - executa uma vez antes de todos testes'); });
afterAll(function () { console.log('afterAll - executa uma vez após todos testes'); });
beforeEach(function () { console.log('beforeEach - executa antes de cada teste'); });
afterEach(function () { console.log('afterEach - executa após cada teste'); });
it('Deve somar os números', function () { console.log('teste calc.somar'); var calc = new Calculadora(); expect(calc.somar(2, 1)).toBe(3); });
it('Deve incrementar um número', function () { console.log('teste calc.incrementar'); var calc = new Calculadora(); expect(calc.incrementar(2)).toBe(3); }); });
No fim as funcionalidades são muito parecidas. Vamos fazer um paralelo dos métodos entre os mundos do Java e do JavaScript pra ficar mais claro:
Java (JUnit)
JavaScript (Jasmine)
Suite
describe
BeforeClass
beforeAll
AfterClass
afterAll
Before
beforeEach
After
afterEach
test
it
assert
expect
O que vem por aí
Finalizando, este foi o primeiro artigo de uma série bem bacana que estamos elaborando (for dummies and ninjas). Nos próximos artigos falaremos sobre Karma, PhantomJS, Matchers, testes de unidade, integração e sistema, e até mesmo, como testar seu HTML que ainda nem existe. Também abordaremos testes mais complexos envolvendo o conceito de Mocks e Spys.
Por fim, falaremos sobre como medir cobertura de código e como integrar todo esse ferramental no build da sua aplicação em um servidor de integração contínua com a ajuda de Gulp e Grunt. Se você é iniciante como eu ou ninja como o Tiago, comenta sua experiência nesse mundo complicado desafiador JavaScript. Ademais, você também pode acompanhar o código que estamos elaborando para os próximos posts no meu GitHub. Comenta aí!