Primeiras aulas do curso Jasmine: Testes automatizados em JavaScript

Jasmine: Testes automatizados em JavaScript

Testes Automatizados - Introdução

Olá, bem-vindo ao curso de testes em JavaScript com o Jasmine do Alura. Nesse curso, a minha ideia é discutir com vocês como escrever testes para códigos escrito em JavaScript. Afinal, JavaScript é uma linguagem que está cada vez mais popular. Os browsers dão suporte, então, toda aplicação faz uso do JavaScript para colocar alguma inteligência no client.

Agora também com essa onda de Node.js, as pessoas têm inscrito códigos servers sides com JavaScript, estão, alguns código de JavaScript que antes eram basicamente manipular a interface, agora estão ficando complicados, cheio de regras de negócio e tudo mais. Escrever teste de JavaScript hoje é fundamental. E se você já conhece alguma coisa de testes, ou já fez algum outro curso da nossa formação, conhece o JUnit ou NUnit, você vê que nem é tão diferente assim.

A grande diferença é na maneira de programar, como escrever o código JavaScript pra facilitar testabilidade. Se você não fez nenhum curso da formação de testes, não tem problema. Aqui eu vou começar bem do básico, motivando você do porquê testar, e como escrever o primeiro teste.

Vamos começar. Eu vou programar aqui e eu vou usar o sublime, que é uma IDE bastante comum, estou usando o MAC aqui, mas você escolhe o seu editor de texto favorito, não vai fazer muita diferença para nós. O browser como vocês viram aqui, eu também estou usando o Chrome, porque não vai fazer muita diferença usar o Chrome ou o Firefox. Dá no mesmo.

Então, aqui de volta para o sublime, a primeira coisa que vou fazer é começar como uma página HTML qualquer. Nem vou ser caprichoso no meu HTML porque não é esse o foco. Eu vou abrir com uma tag script, pra nós começar a programar em JavaScript. Aqui eu estou usando o browser, para facilitar a vida, mas lembre que o que fizemos aqui vai funcionar até pra aquele seu código Node.js, que não é código cliente side.

E como eu falei para vocês, a maneira de programar em JavaScript tem que ser pensada também, então, desde já eu vou programar bonitinho. O primeiro problema que eu quero resolver é o seguinte: imaginem que eu tenho uma classe, e essa classe ela vai receber uma lista de números, e ela tem que me devolver o maior e o menor elemento dessa lista. Aquele algoritmo tranquilo, que você escreveu lá no seu primeiro ano de faculdade, ou no seu primeiro curso de linguagem de programação.

[02:3] Aqui eu vou programar o JavaScript simulando um pouco a orientação a objetos. Então, vou criar minha classe aqui, eu vou chamar essa classe de “MaiorEMenor”. E começar a declarar a minha classe, "var class". E eu vou criar a função aqui que eu vou chamar de “encontra”. A função “encontra” vai receber uma lista de números, e o que eu vou fazer com essa lista de números? Eu vou fazer aquele algoritmo mais convencional, eu vou varrer essa lista inteira e vou ficar guardando o maior e o menor elemento dessa lista.

E vou o tempo todo comparar, o número atual é menor do que o menor de todos? Se for, eu troco. A mesma coisa pro maior. Se for maior de todos, eu também troco. Então, a primeiro coisa que eu vou fazer é o loop, “num.forEach”. Vou abusar um pouquinho dessa ideia do JavaScript, um pouquinho de linguagem funcional. Para cada número eu vou fazer comparação. Se o número atual foi menor do que o menor, eu vou trocar, “menor = num”.

A mesma coisa pro maior, “maior = num”. Vou colocar um else aqui senão não vai funcionar. Eu preciso declarar essas variáveis maior e menor. Eu vou fazer isso aqui fora da classe, até pra usar e simular modificadores de acesso, então, não vou querer que essa variável menor seja enxergada por qualquer um. Vou mostrar pra vocês, “var menor”, e “var maior”. A primeira coisa que eu vou fazer é inicializar esses caras. O menor eu vou inicializar assim. Eu vou colocar o maior número possível de JavaScript, pro número de JavaScript.

Por quê? Porque pensa comigo, se o menor tem um número muito grande, a primeira vez que que cair nesse if, o if vai ser verdadeiro e vai trocar. Então, coloca um número bem grande, porque qualquer um vai ser menor que ele. No maior eu vou fazer exatamente o contrário, eu vou colocar um número bem pequenininho. Óbvio que para terminar esse código, eu preciso fazer alguma função para me devolver um maior e menor, senão não vai ter visibilidade.

Se esse código JavaScript não está muito claro para você, essa jogada de classes, faça lá o nosso curso de JavaScript, que falamos um pouquinho sobre isso. Então, aqui eu vou fazer “return maior”. “pegaMenor”, retorna o menor. E o “pegaMaior”, retorna o maior.

E aqui basta fazer agora o “return clazz”. Então, dando uma olhada esse código, function maior e menor, estou simulando uma classe, eu tenho duas variáveis escondidas, o menor e o maior, e eu tenho o método encontra. O método encontra faz um loop e o tempo inteiro ele olha o número e substitui se ele achou um menor do que o menor atual, ou se ele achou um maior do que o maior atual.

Agora aqui eu vou escrever um teste para ele, vamos praticar igual você fez lá no primeiro código da sua vida. Você escreveu a função, e aí você escreveu um método main, ou alguma coisa que invocava essa função pela primeira vez. Então, vamos lá. "var algoritmo = new MaiorEMenor()”. “algoritmo.encontra”, e aqui vou passar uma lista de números quaisquer, então, 5, 15, 7 e 9. E eu vou imprimir esses números. “console.log(algoritimo.pegaMaior())”, e “console.log(algoritimo.pegaMaior())”.

Então, se eu rodar esse programa, eu espero que a saída seja 15 e 5. Vou salvar isso aqui, Ctrl+S. Vou escolher o diretório. Eu estou usando a pastinha com meu nome aqui, meu sobrenome é Aniche. Vou criar uma pasta que eu vou chamar de “primeiro-js”, para facilitar. E vou chamar esse cara aqui de “teste.html”. Ele até coloriu pra nós. Uma boa ideia. No próximo você vai ver que eu vou fazer isso, já vou salvar arquivo desde o começo, porque tudo fica colorido, mais fácil de ver.

Estou no meu browser, Command+O, file open, para abrir o arquivo. Vou achar o meu arquivo teste HTML. Vou abrir ele. Vamos lá. Eu vou abrir um inspector do Chrome, vou pro console. Dá uma olhada. Ele imprimiu 15 e 5. Está funcionando. O meu código está funcionando, é o que apareceu aqui. Agora, a pergunta que vou fazer para vocês é: bem, programamos, escreveu um teste, uma main que invocou o nosso código e deu certo. Será que eu posso colocar esse código em produção?

Será que ele realmente funciona? Não tem nenhum outro problema nele? Veja só o teste que eu vou fazer aqui. Ao em vez de 5, 15, 7 e 9, eu vou passar para ele 7, 6, 5 e 4. Então, eu espero que o maior seja 7 e o menor seja 4. Vou voltar pro meu browser. Vou dar refresh na página e dá uma olhada. O menor ele colocou quatro, ele acertou. Só que olha o maior, ele colocou um número doido aqui, 5 e a menos 324. Não era o que eu estava esperando.

Eu estava esperando que o maior fosse 7, igual eu passei aqui para ele. Só que veja só, esse número aqui, 5 vezes dez elevado a menos 324, é exatamente o nosso “MIN_VALUE”. Ou seja, o maior nunca fui substituído. Por quê? Dá uma olhada no meu código, esse else aqui, que eu coloquei de propósito para forçar o erro, é um bug. Eu tirei o else e veja só, funcionou, mas o ponto é que quando eu estava programando, e isso acontece no mundo real, você está programando um algoritmo que é complicado, que te dá trabalho, você escreve código errado sem querer.

Você não está pensando em todas as possibilidades. Acontece. Como eu vou descobrir isso? Testando. Eu tenho que testar software. E como que eu tenho que fazer isso? De maneira automatizada. O teste manual é chato, é demorado, é suscetível ao erro, é por isso que ninguém testa, porque não dá para ficar pagando um desenvolvedor ou um testador pro tempo inteiro testar o programa inteiro, que você sabe que, na prática, toda vez que você muda qualquer coisa no seu código você tem que testar ele do começo ao fim. Tudo de novo.

Até porque mexeu em A você quebra B, e tudo mais. A ideia então, é fazer um programa que testa o seu programa. Este código é quase um teste automatizado, porque eu tenho um cenário aqui, 7, 6, 5 e 4 é um cenário, e toda vez que eu testo o que eu faço é pensar em cenários. Eu quero ver o que acontece com a minha aplicação se eu passar números de ordem crescente, números em ordem decrescente, números em qualquer ordem, uma lista com um único elemento e assim por diante.

Eu executo uma ação e eu valido uma saída. Isso aqui é quase automatizado, porque veja só, o cenário está automatizado. Depois que eu escrevi 7, 6, 5 e 4 é automático. Invocar o método encontro também, meu programa sempre vai invocar o método encontro. O único problema é a saída. Porque ainda depende de um ser humano olhar para ver se está funcionando.

O que eu poderia fazer para corrigir é o seguinte, vamos lá. O “pegaMaior” eu sei que é 7, e o “pegaMenor” tem que ser 4. A. Se eu rodar false true, era pra imprimir true e true, se tudo tivesse funcionado. Não funcionou. Porque ainda tem esse else aqui. Deixa eu tirar. Se eu rodar agora é true e true.

Veja só, eu escrevi um código agora que é totalmente automatizado, tem um cenário automatizado, uma invocação de método automatizado e um teste que é automatizado, porque o meu computador sabe que agora o “pegaMaior” tem que ser 7, e que o “pegaMenor” tem que ser 4. É o que eu espero. Isso é um teste automatizado.

Só que isso é ruim ainda, porque imagina só um programa de verdade vai imprimir um milhão de trues, um milhão de falses, você não vai saber muito bem o que deu false, o que deu true. E é aí que vai entrar o framework de teste automatizado, que é o Jasmine.

O que o Jasmine faz pra nós? Ele facilita não só a escrita do teste, mas essa saída final, se der um erro, ele vai mostrar onde deu erro para mim, qual foi o teste que falhou. Vou mostrar para vocês. O Jasmine é uma biblioteca JavaScript, como qualquer outra. Você baixa no site do Jasmine. No primeiro exercício do curso você vai ter a opção para baixar, o link certinho. Você vai baixar o arquivo, Jasmine standalone 2.0. Aqui eu tô usado a versão 2.00. Talvez quando você fizer esse curso tenha uma versão mais recente, se ainda é 2 está valendo.

Vou deszipar ele aqui. Ele deszipou pra essa pasta Jasmine standalone. E dá uma olhada, aqui está a biblioteca, e essa pastinha lib é toda a biblioteca do Jasmine, que pra nós não importa muito. É uma biblioteca, não vou mexer nela. Para nós se importam três coisas, a pasta source, a pasta spec, e o SpecRunner. Spec é como ele chama o teu teste automatizado, ele chama de spec. É bastante comum, tem bastante framework que faz isso. Source é onde vai estar o nosso código fonte.

SpecRunner é um cara bonitinho que vai mostrar pra nós a interface. Então, vamos lá. O que eu vou fazer é abrir o SpecRunner. Vou clicar duas vezes nele, e dá uma olhada. Ele já rodou. O Jasmine e já vem com alguns códigos de exemplo, ele tem a classe Player. Ele executou esse teste, "should be able to play a song", e assim por diante, cada um desses verdinhos aqui que estou passando o mouse é um teste que ele rodou.

Vamos abrir esse código no sublime para dar uma olhada. Aqui eu vou abrir a pasta inteira no sublime para facilitar. A classe player é uma classe do JavaScript convencional, um código de JavaScript, e eu vou abrir aqui um player spec, que é o quem ele rodou. Esse aqui é um código do teste. Nesse momento, não assusta, não tenta entender, vamos escrever isso do zero. Por que ele rodou esse player spec? Dá uma olhada no SpecRunner.

O que ele faz aqui não tem segredo. Veja só que aqui eu estou importando as bibliotecas do Jasmine, tem os JavaScripts, tem o CSS pras coisas ficarem bonitas. Aqui são as minhas bibliotecas, e em seguida, os specs. O que vamos fazer é escrever os nossos specs. Então, a primeira coisa que eu vou fazer é pegar aquele nosso código maior e menor e jogar aqui dentro. Eu vou criar aqui um arquivo que eu vou chamar de “MaiorEMenor.js”.

O que vai ter nele? Aquele nosso código fonte do “MaiorEMenor”. Vou dar um Ctrl+c nele aqui e vou colar no outro projeto. E vou batizá-lo de “MaiorEMenor.js”. No SpecRunner agora eu vou incluir esse cara. Então, eu vou copiar essa linha do include, e source “MaiorEMenor.js”. Meu código fonte está lá, agora eu quero testar. Na pastinha spec eu vou escrever o arquivo que eu vou chamar de maior e MaiorEMenorSpec.js.

Como que começa a escrever esse teste? É a API do Jasmine, e é o que eu vou mostrar para vocês agora. Todo começo de teste tem o que o Jasmine chama de "describe", o describe você vai passar para ele uma informação em português, por exemplo, em língua natural, que vai explicar o que estamos testando. Geralmente, nós colocamos o nome da classe, então, estou testando aqui o “MaiorEMenor”. É o meu teste.

O describle ele recebe uma função. Function. Dentro desse describle é onde eu vou escrever os meus testes, e por testes entenda cada possível cenário do meu código. Então, o primeiro teste que eu vou fazer é um teste que eu vou chamar de "deve entender números em ordem não sequencial". Veja só que o nome do meu teste já deixa bem claro o cenário que eu vou passar, "números em ordem sequencial".

E veja o nome do método que eu usei aqui, eu usei it. Por que it? Porque se você pegar o código em inglês geralmente o pessoal vai escrever "it should e blá blá blá", então, "o código deve tal coisa", por isso eu usei o deve aqui. Em inglês ia ser “it should”, eu vou programar em português, não tem problema. Então, esse primeiro texto aqui é uma explicação do teste. Eu geralmente uso para deixar claro o cenário que eu estou testando. "Deve entender números em ordem não sequencial". Essa é uma outra função. "Function".

Aqui dentro agora eu vou programar. Eu vou programar exatamente o código que eu fiz antes, vamos lá, é a mesma. “var algoritmo = new MaiorEMenor()”, “algoritmo.encontra” eu vou passar aquela lista 5, 15, 7 e 9, e eu sei que a saída é 15 pro maior e 5 pro menor. Como eu vou fazer essa verificação? Antes era o console.log, e usamos igual a igual. Aqui eu vou usar a API do Jasmine. Como funciona?

Eu vou sempre usar a palavra expect. E dentro do expect eu vou passar o que eu calculei, o algoritmo “pegaMaior”, eu espero que ele seja igual a 15. Dá uma olhada, o API é bem fácil de ler. Você entende que eu espero que o “pegaMaior” seja igual a 15, e eu espero que o “pegaMenor” seja igual a 5.

É exatamente igual o outro código que fizemos. Dá uma olhada da linha 32 para baixo. Igual. A diferença é que em vez de “console.log”, eu usei o expect do Jasmine. Então, o teste automatizado é igual aquele código que você escrevia, dá um ew na sua classe, invoca a função que você quer testar e verifica se a saída é o que você quer, de acordo com o cenário que você passou.

E o SpecRunner? Eu tenho que incluir essa especificação, “spec/MaiorEMenorSpec.js”, e agora eu vou rodar aqui. Dá uma olhada. Apareceu maior e menor. Eu aqui só para tirar, vou tirar as coisas das demonstrações do Jasmine que não precisamos. Vou deixar só o nosso. Então, “MaiorEMenor”, “MaiorEMenorSpec”. Roda de novo. Olha só, “MaiorEMenor”, deve entender números em ordem não sequencial. E ele está verde, geralmente, os frameworks pintam de verde quando o true dá certo. Se tivesse dado errado ele ia ter pintado de vermelho. Quer ver? Vamos ver um teste em vermelho aqui.

Vamos escrever o próximo teste. Como eu faço isso? A mesma coisa "it" e o próximo cenário. "Deve entender números em ordem crescente". Function, “var algoritmo = new MaiorEMenor()”. “algoritmo.encontra”, vou passar para ele que será 5, 6, 7 e 8, e eu espero que algoritmo “pegaMaior”, seja "toEqual" a 8 e o menor é 5.

Vou rodar. Tudo verdinho. Vamos forçar o bug, colocar um else aqui. Vamos ver... Tudo continua verde porque o bug era em ordem decrescente. Então, vamos fazer o mesmo teste para a ordem decrescente. Aqui eu vou até fazer um Ctrl+c pra não ter que digitar tudo de novo. Cuidado com o Ctrl+c, pra você não dar tudo certo. Em ordem decrescente aqui vai ser 8, 7, 6 e 5. Ele usa a palavra expect, mas o termo comum na área de teste é assert. Os assert são os mesmos. Eu vou rodar e dá uma olhada.

Três testes, um falhou, e ele ai me falar qual. "Deve entender números em ordem decrescente", eu esperava que isso aqui fosse igual a 8 e não é, por algum motivo não é, bug do meu código. Ficou vermelho está errado. Volto pro meu código e, realmente, tem um bug. Corrijo o bug e rodo de novo. Estou dando refresh na página para rodar de novo. Não tem segredo.

Tudo verde. Tudo verde me dá segurança, me diz que está tudo funcionando. E qual vantagem dessa segurança? A vantagem é que eu posso vir nesse código aqui e muda a implementação. Passo jogar isso aqui fora e implementar de outro jeito. Eu poderia ordenar lista de números, pegar o primeiro elemento como menor e o último elemento como maior. Uma outra implementação. Como que eu vou garantir que funciona? Eu vou vir aqui e vou rodar meu teste.

Então, isso é um teste automatizado. Um teste automatizado é alguma coisa que dá um new no que eu quero testar, se eu estou usando classes de JavaScript, invoca o comportamento que eu quero testar passando um cenário em particular e dado o cenário, depois eu faço as asserções, as validações pra ver se meu programa funcionou. Isso é teste manual.

Olha o temo que ele levou para rodar. Ele mostra ali no canto direito da tela. Zero pontos zero zero zero quatro segundos. Muito rápido. Muito mais rápido que um ser humano, imagina você testando isso aí de maneira manual, ia demorar demais. Então, isso é um teste automatizado. Veja só que não tem segredo, é fácil. Meu código JavaScript é simples, o teste é simples igual e você vê que ao longo do curso eu vou mostrar que o seu teste nunca vai ser muito diferente disso.

Se seu código está bem escrito, seu teste sempre vai ser simples. Esse é o segredo. Então, nesse capítulo mostrei para vocês as vantagens do teste automatizado, ele roda rápido, ele me dá segurança na refatoração, ele não é tão chato igual é fazer um teste manual.

E eu mostrei o Jasmine, como fazer ele funcionar. Baixei a biblioteca no site e saí escrevendo as specs, usando o describe, usando o it. Passando essas funções anônimas. Bem simples. Esse é o primeiro capítulo, mostrei para vocês o começo de um teste automatizado. Eu vejo vocês no próximo capítulo, que a coisa vai ficar mais legal. Obrigado.

Testando o que importa em um projeto real - Jasmine Aula 2

Bem vindo à segunda aula do curso de testes em java script com o Jasmine. Na primeira aula você aprendeu a testar a classe “MaiorEMenor”, escrever um monte de testes para ela. Nessa segunda aula a ideia é continuar a escrever testes, até para você praticar isso e a ideia de testes automatizados ficar natural. Agora, em um outro problema, claramente, e começar a discutir um pouquinho de como escrever bons testes e pensar em cenários, etc.

Eu vou aqui pro meu sublime, que eu tinha o código exatamente de onde eu parei, só que agora eu vou começar uma nova classe. Eu vou criar um arquivo aqui que eu vou chamar de “Paciente.js”. Imagine que estamos fazendo um sistema médico, onde eu tenho pacientes, e esses pacientes eles passam por consultas e tudo mais.

Vou começar aqui com function “Paciente”, e a função vai receber um nome, uma idade, um peso e uma altura. Eu vou aqui programar também pensando um pouquinho minha orientação a objetos e tudo mais. Var clazz e ele já retorna classe. O primeiro método que meu paciente vai ter é o que vou chamar de imprime. Um método bem simples, ele vai só mostrar um alert para mim na tela. Então, alert, o nome da pessoa, a idade em anos. Simples. Vamos para o próximo.

O próximo é mais legal. Vou chamar esse método de batimentos. Aqui eu vou calcular a quantidade de batimentos que o coração dele já deu na vida. Como eu vou saber isso? Bem, em média um coração bate por volta de 80 vezes por minuto. Então, vou pegar a idade dele, vou multiplicar por 365 dias em ano e vou multiplicar por 24 horas, que é o que eu tenho em um dia, vou multiplicar por 60 minutos, que é o que eu tenho em cada hora, e vou multiplicar por 80. Isso aqui é uma aproximação do batimento, da quantidade de vezes que o coração da pessoa bateu.

E a próxima função que é importante para a nós, eu vou chamar de IMC. IMC é aquele índice de massa corpórea, aquela conta que é feita com o teu peso e com a tua altura, que te disse se você está mais ou menos saudável. Então, a forma de IMC, você pode até olhar na internet é o peso dividido pelo quadrado da altura. Obviamente, os médicos pegam esse número e te falam se você está saudável. Eu tenho essa classe “Paciente”, vamos começar a testar ela.

Pra testar ela vamos lá na pasta spec, já aprendemos isso. Então, todo o código está no source. Eu venho no spec, spec na pasta spec, por questão de organização. Então, todo spec começa com um describe. Eu vou descrever um paciente, vou passar uma função anônima, e vou escrever o primeiro teste. It “deve calcular o IMC”, function. A primeira coisa é criar a classe “Paciente” que é a classe que eu quero testar. Vou fazer new paciente, ou paciente Guilherme, que tem 28 anos, pesa 72 quilos e tem 1.82 de altura.

O método que eu quero testar é o método IMC, “guilherme.imc”, e eu vou colocar aqui “var imc” da pessoa. Eu vou fazer aqui “expect(imc).toEqual”, e o IMC dele tem que ser 72 dividido 1.82, vezes 1.82. É o IMC que eu espero dele. Escrevi o teste, tenho o código de produção, vou rodar. Dá uma olhada, eu rodei e não mudou nada, só rodou o “MaiorEMenor”. Por quê? Porque eu não posso esquecer de ir no “SpecRunner” importar a classe.

Faltou incluir o paciente, e faltou incluir o “PacienteSpec”. Rodou, o teste está verde, o IMC deu certo. Agora, a pergunta que eu tenho para você é o seguinte: esse código funcionou? Para o paciente Guilherme, que tem 28 anos, 72 quilos e 1.82. Será que esse código funciona para outros pesos e alturas? Como garantir isso? Só escrevendo um teste. Veja só o que eu vou fazer, eu vou colocar aqui o “deve calcular o IMC 2”. Eu vou colocar outra altura qualquer aqui, então, serão 82 quilos e 1.77. E mudar a fórmula também, 82, 1.77 por 1.77. Salvei e rodei.

O “deve calcular IMC” e “deve calcular IMC 2” passaram, eu estava esperando isso. Só que a pergunta é: eu testei agora para 72 quilos, 1.82 de altura, 82 quilos, 1.77 de altura, e para os outros? O problema é: eu vou entrar nesse looping infinito de testar todos os possíveis cenários e não dá, a quantidade de combinações é gingante, eu não consigo. O que eu faço? Nesse caso, usamos uma coisa na área de testes que nós chamamos de classes de equivalência, o que é uma classe de equivalência? Uma classe de equivalência é um conjunto de cenários onde todos eles exercitam o código da mesma maneira.

Para o nosso código paciente, na função IMC em particular, não importa o peso, não importa a altura, o cálculo é sempre o mesmo. Então, o ponto é: o cenário 72 quilos e 1.82, do ponto de vista do teste é idêntico a 82 e 1.77, e a prova disso é que se por algum motivo tiver um bug na fórmula, um vezes 2 aqui sobrando, os dois testes falham. Então, de nada adianta eu ter dois testes que sempre passam juntos e sempre falham juntos.

Isso mostra que estamos de certa forma testando o mesmo cenário. Nesses casos, o que que eu faço? A boa prática é um único teste por classes de equivalência. Isso vai facilitar sua manutenção e, obviamente, o seu desafio é encontrar as várias classes de equivalência diferentes. Que são, de novo, cenários que exercitam partes diferentes do seu código. Quando tínhamos lá no maior e menor, com nosso loop tínhamos o cenário de um único número na array, porque meu código pode funcionar diferente, n números, em ordem crescente, decrescente e tudo mais.

O teu exercício é pensar nessas várias classes de equivalência, é isso que faz a diferença. Mas percebeu que tem dois testes iguais? Joga fora e tenha um só. Aproveitando aqui, outra coisa que eu vou mostrar para vocês é que eu tinha “var imc” e colocado variável, mas eu posso fazer inline, muitos desenvolvedores preferem fazer inline, tudo continua funcionando do mesmo jeito. Agora, a próxima classe que eu vou fazer é a classe consulta.

Vou na minha pastinha source, vou criar aqui o “consulta.js”. E uma consulta, “function Consulta”, vai ser com um paciente e uma lista de procedimentos que ele fez naquela consulta. Se a consulta foi particular ou se ela foi pelo convênio, ou se ela é um retorno de uma consulta que foi realizada no passado. Var clazz, já estamos acostumados com isso. O método que eu vou dar aqui é um método que chama “preco”. Esse é o cara que vai calcular o preço da minha consulta.

Como vai funcionar? A regra é a seguinte, se for retorno não paga nada, o valor da consulta é zero. Se for particular, ele vai multiplicar o valor da consulta, mas como eu cálculo o valor consulta? De acordo com o procedimento, eu tenho um valor diferente, e eu posso ter vários procedimentos. A minha implementação pra isso vai ser o seguinte, se for retorno já vou retornar zero desde o começo. Vou criar uma variável “precoFinal”, e vou fazer um loop nessa lista de procedimentos. Então, para cada procedimento na lista a regra vai ser o seguinte.

Se o procedimento for raio-x, então, eu pego o preço final e somo 55, que é quanto custam um raio-x, else if. Se o procedimento for um gesso, eu vou somar 32 reais. Caso contrário, o preço do procedimento é padrão e é 25. Acabou loop. Se for particular, eu dobro o valor, preço final vezes igual a dois, e eu retorno o preço final. E a nossa implementação aqui no cálculo de preço. Veja só que eu tenho uma série de parâmetros diferentes e dá para exercitar esse código de maneiras diferentes.

Então, eu vou ter vários testes, por exemplo, um pra retorno, um para particular, um pra procedimentos genéricos, um pra procedimento pra raio-x, outro pra gesso, etc. Vamos para o teste. O primeiro teste que eu vou fazer, vou lá na pasta spec, então, criar esse cara. Vou salvar como “ConsultaSpec.ks”. Describe consulta. Vamos escrever essa infra que eu preciso. Function. O primeiro cenário que eu vou testar é o retorno, porque o cenário é mais fácil. Então, "não deve cobrar nada se for um retorno".

Vou criar um paciente, porque eu preciso de um paciente.. Meu paciente Guilherme, 28 anos, 72, 1.80 de altura, e eu vou criar uma consulta. New consulta, Guilherme, não vou passar nenhum procedimento, que eu não preciso. É particular. É um retorno. Eu sei que eu espero que a “consulta.preco” seja igual a zero. SpecRunner de novo, adiciono as classes.

Então, “Consulta”, “ConsultaSpec”. No browser, rodei, tudo verde meu teste passa. Vamos só ver o teste falhar, é sempre uma boa prática, se eu colocar return 1 o teste falha. Coloca zero de novo. Teste funciona quando implementação está certa e falha quando a implementação está errada, eu preciso saber isso. Então, agora vamos para o próximo cenário, eu vou garantir que um procedimento comum é cobrado 25 reais.

It, deve cobrar 25 por cada procedimento comum. Function. Vou copar essas duas linhas aqui que elas são parecidas. A diferença é que vou mudar os parâmetros, vou passar dois procedimento. Proc1 e proc2, o nome do procedimento não importa muito. Aqui não é particular e também não é um retorno, se não ele não vai conseguir calcular. Eu espero que o preço da consulta seja 50. Rodando, tudo verde, tudo funcionando, está perfeito.

Agora o que é uma discussão interessante, veja o que eu passei dois parâmetros, dois procedimentos, eu podia ter passado 3, 4, 5, 6, 20, 30, 40. Mas qual a diferença de 2 para 3 procedimentos e para 4 procedimentos? Para esse código, em particular, nenhuma. Então, eu penso, dado que eles são da mesma classe de equivalência em um cenário mais simples. Se eu quiser fazer com 3, não tem muita diferença. Se colocar aqui 75 o teste vai passar.. Um, dois, três é fácil, é pequeno e tudo mais.

[112:28] Mas não vou fazer um teste com 30 procedimentos sendo que o teste com três é a mesma coisa. Então, começa a pensar nisso também, na classe de equivalência faz o mais simples, o mais claro de ser lido. Agora, vamos lá para o próximo teste, vou chamar de “deve cobrar preço específico dependendo do procedimento”, function. Vou criar o Guilherme do mesmo jeito. Ctrl+c e Ctrl+v aqui, vou criar consulta, passando o Guilherme.

A lista de procedimento vai ser assim, procedimento comum, raio-X, outro procedimento comum, gesso. False, false. O que eu espero? Espero que o preço seja igual a 25, que é o procedimento comum. 55 é o raio-x, 25 é outro comum, 32 que é o gesso. Vamos ver? Se eu rodar, tudo continua passando. Já escrevi três testes com vocês. Não cobra nada se for retorno, 25 reais cada procedimento, deve cobrar um preço específico.

Veja só que eu tenho mais cenários, eu não testei o caso do particular, eventualmente o caso do particular com um procedimento especial, raio-x, gesso, etc. O que eu quero que saia dessa aula para vocês é a parte de classes de equivalência. Essa é a parte importante. Então, começou a escrever teste, pensa nas diferentes classes de equivalência. Se pensou dois cenários que pertencem à mesma classe, escreve um único teste.

E tenta optar pelo mais simples, pela menor classe de equivalência possível. Aqui eu poderia passar dois procedimentos. Eu não quero que você passe quinze, porque não vai fazer diferença, só vai dar trabalho. Então, no exercício você vai continuar escrevendo teste para essa classe consulta, e continua pensando nos outros cenários.

Um detalhe que eu não falei, você deve ter reparado naturalmente, que a palavra consulta que você escreve aqui nunca aparece aqui, é pra isso que serve o describe. Se eu colocar à consulta X, ele vai exibir consulta X. Foi um exemplo bobo, mas mostra pra você que o texto que eu escrevo ali é o que aparece aqui. Então, a segunda aula é isso, classe de equivalência, continuar testando, pensar em cenários diferentes para exercitar o seu código. Obrigado por esse capítulo e espero você no próximo.

Códigos de Teste Legíveis - Jasmine Aula 3

Olá, bem-vindo ao capítulo 3 do curso de testes em JavaScript com Jasmine. Até agora você aprendeu a escrever testes e entendeu que testes são um cenário, uma ação, uma validação. Pensou em classes de equivalência, escrever um único teste pra equivalência, um teste mais simples. E essa bateria de testes está crescendo, você já viu que isso é legal, que você está testando caminhos diferentes do seu código, então é natural que você tenha muito o código de teste nesse momento.

É até bastante comum que no mundo real você tenha até mais códigos de teste do que de produção, porque você viu que um if no código de produção gera 4, 5, 6 linhas no código de teste. Então, o ponto é que dado que essa bateria cresce muito rápido, o código cresce muito rápido, você tem que escrever um código fácil de ser mantido, do mesmo jeito que o código feio te atrapalha na produção, ele também te atrapalha no teste. Então, vamos lá, de volta aqui com o nosso código.

Dá uma olhada na nossa "ConsultaSpec". Se você terminou todos os exercícios está maior do que o meu, mas veja, eu tenho linha repetida em todos eles. Essa aqui é o var Guilherme. Em todos os meus códigos aqui eu escrevo "var Guilherme", repetidamente o mesmo código. Qual o problema disso? O problema é que imagina que essa linha mude, eu tenho que passar mais um parâmetro aqui, um outro número qualquer. Eu vou ter que mudar isso em todos os lugares. Estranho, problemático, código repetido você já sabe dos problemas, eu nem preciso ficar discutindo muito sobre isso.

Então, eu vou mostrar pra vocês como fazer para resolver, como fazer para escrever esse Guilherme uma única vez e deixar de repetir. Eu preciso desse Guilherme em todos os métodos de teste, eu vou precisar que essa variável tenha um escopo maior e seja enxergada por todos os testes. Eu vou ter uma função qualquer, essa ideia e essa função qualquer que vai fazer para mim lá o Guilherme new paciente.

Inicializar coisas num teste é comum. É comum que vários testes, na mesma bateria, dentro do mesmo describe, tenham, por exemplo, um mesmo objeto paciente, ou tenha um começo igual. Então, o Jasmine já espera isso e ele dá para nós o que ele chama de "beforeEach". O "beforeEach" recebe uma função, que é exatamente essa função que escrevemos, e o que ele faz? Ele vai executar essa função antes de cada teste. Para mostrar até eu vou escrever aqui "console.log("beforeEach")".

Ou seja, antes de rodar esse teste "não deve cobrar nada se for um retorno" ele roda o beforeEach. Antes de rodar o segundo teste ele roda o beforeEach, antes de rodar o terceiro teste ele roda o beforeEach. Voltando pro nosso browser, olha ali, três beforeEach. Um para cada teste. Essa é a ideia, vou apagar o "console.log" que é feito, eu não preciso dele. Essa é a ideia, se você tem um código repetido em todos os testes, isola isso e faça o uso do beforeEach.

Eu, em particular, sempre tenho beforeEach no meu código. Todo o texto, todo código repetido vai para ele. A primeira boa dica é: use beforeEach. A segunda dica, que eu usei describe lá em cima, mas eu posso ter outros subníveis de describe se isso me ajudar a descrever melhor meus testes. Então, por exemplo, imagina que eu tenho uma bateria de testes que são consultas do tipo retorno, eu poderia agrupá-los em outro describe.

Vou levar esse it aqui para dentro. Dar um tab pra ficar bonito. Então, consultas do tipo retorno, eu vou colocar um outro subnível aqui que vai ser consultas com procedimentos, porque esses dois testes embaixo fazem os testes dos dois procedimentos para mim, eu vou levar os dois. E o que isso muda? O teste é o mesmo, a diferença é o relatório, dá uma olhada, consulta, consultas do tipo retorno, consultas com procedimentos, e ele vai só separando melhor o relatório.

Agora eu usei os describes não só para separar os testes de cada uma das minhas classes, mas também para separar comportamentos maiores, responsabilidades maiores dentro de uma classe em particular. Você pode ter describes alinhados e ele te dá um relatório mais amigável pra isso. Se você tiver conjuntos de testes que são semelhantes, até faz algum sentido agrupar em describes, esse relatório é em português, então é legível e vai te ajudar caso seu código tenha algum problema, vai ficar mais fácil de entender esse problema.

Próximo passo. Dê uma olhada no código que usamos para criar um paciente. New paciente Guilherme, 28 anos, 72 quilos, 1.80 de altura, quatro parâmetros. Parece fácil. Agora imagina uma entidade paciente que fosse mais complicado, com dez campos para endereço, carteirinha de vacinação, número do convênio, um monte de informação. Imagina só em todo lugar você tem que dar um new e passar estado completo.

Pensa o seguinte, aqui eu estou usando o paciente para testar a consulta, mas o paciente é provavelmente uma entidade importante no meu sistema, então, eu vou ter esse new paciente em outros lugares. Toda vez que minha entidade mudar, eu vou ter que mudar em vários lugares. Se ela é complicado de ser criada, eu vou ficar passando um monte de parâmetro pra ela, que às vezes eu nem preciso, nem quero. Eu passo o nome Guilherme porque é obrigatório, mas o nome pouco importa para esse teste.

Eu tenho uma entidade que é grande, é complicada de ser criada, que tem dados que eu não preciso usar o tempo inteiro e eu quero facilitar minha vida, com é que fazemos? Essa aqui é uma cópia do que fazemos em linguagens como C#, em Java, e que para mim faz total sentido também em JavaScript. Veja só o que eu vou fazer, no meu source aqui eu vou criar um outro aqui e vou chamar de "PacienteBuilder".

E o nome dele já diz, o objetivo vai ser facilitar a criação de pacientes, a palavra builder vem lá do padrão de projeto Builder, se você não conhece ele direitinho faz o nosso curso de padrão de projeto em Java, em C#, que você vai entender o que é o builder. Mas a ideia é facilitar a criação de objeto. Qual? O objeto paciente. Primeira coisa que eu vou fazer é definir valores padrões para cada um dos atributos.

Então, o nome vai Guilherme. A idade vai ser 28, o peso vai ser 72, e a altura vai ser 1.80. Eu vou criar a classe. "var clazz", "return clazz", e o primeiro método que eu vou fazer nele é o método que todo builder tem, que chamamos de "controi". Esse método vai retornar pra nós um paciente com os dados que ele tem salvo, o nome, idade, peso e altura. Esse código aqui já funciona, então se eu for aqui no meu "ConsultaSpec", ao invés de eu fazer new paciente eu posso fazer "new PacienteBuilder().constroi()".

Ele já vai me dar um paciente com os dados que eu preciso. Muito mais simples. Em todo lugar agora que eu precisar de um paciente, ao invés de eu fazer new paciente e passar os dados fixos, eu passo paciente builder ponto constrói e ele vai passar para mim, Guilherme, com um peso específico e tal. "Mas aqui na minha classe paciente, cadê os testes de paciente, vou precisar variar o peso, a altura, preciso mudar", é fácil.

Vamos aqui no nosso builder e da métodos para isso. Então, por exemplo, se a idade é importante e precisa mudar, eu posso criar um método que eu vou chamar de "comIdade", que eu vou passar um valor qualquer aqui, e esse cara vai fazer assim, "idade = valor". Que eu vou até fazer um "return this". Já explico o porquê. "Ah, preciso mudar o peso", "comPeso : function (valor)", e eu mudo o peso. O peso é igual ao valor que chegou, return this.

Percebeu o que eu estou fazendo? Estou criando métodos no meu builder que modificam os valores padrão. Então, o ponto é, se eu estou aqui no meu consulta spec e eu preciso mudar o peso do paciente, eu faço com peso e passo 50, ".constroi". Se precisa mudar a idade, com idade de 12 anos, ".constroi". Eu posso mudar, mas se não for importante eu tenho um valor padrão. Essa é a sacada do builder, ele facilita a criação de objetos pro teste e nele eu ponho qualquer método que me ajude.

Então, "comIdade" para mudar a idade, "comPeso", etc, mas eu sei que tem valores padrão, que não estão preenchidos de graça para mim, essa é a ideia. Agora, código mesmo porque aqui no meu builder eu retornei this, pra conseguir escrever de maneira fluente, como chamamos, então, eu faço com peso 10 ponto, que ele vai me deixar invocar o método constrói, porque o método "comPeso" retorna o this, que é o próprio objeto. Então, ele vai ter um método constrói.

Vamos ver se funciona. No "SpecRunner" eu não posso esquecer de importar o "PacienteBuilder". Não achou o "PacienteBuilder" porque eu errei a pasta, coloquei no source. Idealmente tem que estar na pasta spec, que tem mais a ver com os teste. Poderíamos mover esse código pra lá. Vou ter que mover aqui pelo Finder, porque o sublime não está movendo. Então, vou pegar a pastinha source, "PacienteBuilder" eu vou levar para a pastinha spec e fica melhor. O que é de teste na pasta de teste.

Volto aqui pro "SpecRunner", aqui ponho spec de volta, volto pro meu teste, rodo. Tudo continua passando, já estávamos esperando isso. Isso é o que nós chamamos de test data builder. São builders para dados de teste, para cenários de teste. O que ganho com isso? De novo, fica fácil criar cenários se a minha classe paciente um dia mudar, eu não vou ter que sair mudando em todo lugar fazia "new paciente" no meu teste. Eu vou mudar simplesmente aqui no meu builder.

Vou acrescentar um parâmetro a mais aqui, então, var novo parâmetro. Vou colocar lá no método constrói e assim por diante. Vai ficar fácil, eu mantenho em um lugar só. Então, veja só que é um pouquinho do que falamos de encapsulamento, a lógica de criar um paciente está encapsulado no meu teste data builder. Então, nesse capítulo eu discuti com você boas práticas para você escrever código de teste de qualidade. Falei pra você não repetir código, mostrei pra você o beforeEach, que vai ser executado antes de cada teste.

"Ah, mas eu tenho comportamentos que vou utilizar em vários outros teste também, como eu aproveito?" Nada te impede de criar outras classes de teste que tenham lá algum comportamento que você precisa. Lembre-se: favoreça a testabilidade, facilite seu teste. Isso vai implicar em escrever infraestrutura de testes. Não tenha vergonha e não tenha medo disso, escreva o código que te ajudar pro teste, pra te ajudar a manter o código de testes.

Mostrei o beforeEach, mostrei o describe, que você pode ter vários describes alinhados e isso te dá um relatório mais elegante, mais formatado e mostrei para vocês aí o "PacienteBuilder". O test data Builder, que é o nome genérico do padrão de projeto, que são classes que ajudam a montar cenários de teste. A vantagem: encapsular o processo de criação de objetos de teste em um único lugar, fica fácil de utilizar, fica fácil evoluir, facilitando a manutenção do teste.

Tudo que você puder fazer para escrever um código de testes simples e fácil de ser mantido, faça. Cuide do código do seu teste. Então, era isso que eu queria falar nessa terceira aula para vocês. Obrigado e até a próxima aula.

Sobre o curso Jasmine: Testes automatizados em JavaScript

O curso Jasmine: Testes automatizados em JavaScript possui 75 minutos de vídeos, em um total de 38 atividades. Gostou? Conheça nossos outros cursos de Automação e Performance em Front-end, ou leia nossos artigos de Front-end.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Automação e Performance acessando integralmente esse e outros cursos, comece hoje!

  • 1124 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

Premium

  • 1124 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$75
à vista R$900
Matricule-se

Premium Plus

  • 1124 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$100
à vista R$1.200
Matricule-se

Max

  • 1124 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$120
à vista R$1.440
Matricule-se
Procurando planos para empresas?
Acesso por 1 ano
Estude 24h/dia onde e quando quiser
Novos cursos toda semana