Não faça testes, faça specs!

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.

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

 

11 Comentários

  1. Rafael Ponte 10/08/2017 at 08:20 #

    Excelente artigo (série), Rapha!

    Eu também sou iniciante no mundo frontend, meu forte de fato é backend, então, assim como você, eu teria que aprender TUDO de novo sobre aplicar as práticas de engenharia que utilizamos há MUITOS anos no backend em Java.

    Sua série sem dúvida vai facilitar muito minha vida, pois cedo ou tarde eu sei que vou cair nesse mundo pra valer e já chegar tendo idéia de como escrever testes, rodar build automatizado, medir a cobertura e tudo mais fará toda a diferença. Melhor ainda, conhecer tais práticas e saber avaliar quais delas são válidas em determinados cenários.

    Um abraço e, como sempre, estou de olho nos seus artigos!

    PS: os testes em JavaScript tendem a ter melhor clareza devido a natureza da linguagem ser dinâmica. No Ruby, Python e outras temos resultados semelhantes. Sobre essa sintaxe ser consideado BDD, eu tenho minhas dúvidas pois no final das contas é praticamente a mesma coisa de um teste de unidade com jUnit, só há uma sintaxe sem ruídos da linguagem.

  2. Raphael Lacerda 10/08/2017 at 19:00 #

    rapaz, vou te dizer que concordo plenamente contigo.

    Acho uma frescurada ficar definindo essa quantidade de siglas para testes.

    Pra mim é tudo teste e vamos nessa.

    Na verdade, o nome do padrão deveria ser TFL – testes fáceis de ler

  3. Flavio Mendes Duarte da Rocha 11/08/2017 at 04:50 #

    Eu gosto de programa,por isso irmão qualquer publicação a respeito do mesmo por favor não hesite.

  4. Eder Fonseca 11/08/2017 at 09:10 #

    Muito bom o artigo!!! Irei acompanhar essa série com certeza!

    Obrigado e parabéns.

  5. Josiel Santos 12/08/2017 at 06:15 #

    Olá! Muito interessante a série de artigos.
    Não me lembro de ver por aí uma “comparação” dessas tecnologias focando na parte de testes.
    Só tenho um toque, tem como colar os códigos nos textos ao invés de postar o screenshot? Sou cego e assim ficaria muito mais tranquila a leitura dos posts.
    Obrigado e continue que vai ser sucesso! 🙂

  6. Raphael Lacerda 12/08/2017 at 12:30 #

    Blz josiel.. esse código inicialmente ainda não é mão na massa especificamente, é só uma demonstração bem básica e o Tiago colocou o link para o github

    Mas fica tranquilo.. refatoração vindo em 3 …. 2 …. 1…

  7. Lucas Bulcão 13/08/2017 at 23:21 #

    Excelente artigo, Raphael!! Com certeza irei acompanhar essa série, pois aborda um assunto muito útil e está sendo passado de forma bem bacana e fácil de entender. Pegando um gancho no título da série, peço-lhe que não faça amor, faça novos artigos. A comunidade agradece! Parabéns!

  8. Tiago Wesley 21/08/2017 at 09:13 #

    Parabéns Raphael e Tiago Lage

  9. Aurelio 22/08/2017 at 14:28 #

    Achei o tema “respetacular” espero que consigam postar as sequências deste artigo com o menor intervalo que conseguirem. Estarei acompanhando…

Deixe uma resposta