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).
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
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:
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', () { .(); calc = (); (calc.(, )).(); });
(, () { .(); calc = (); (calc.()).(); }); });
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í!