DevOps e Testes com Spring (Unitário, Cobertura, API, TDD, Sonar, Jenkins, etc)
Published: 2020-12-13 22:41:23

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f8opnxtxeunoo1b7kkbp.png)

O Sonar e o Fortify são ferramentas de análise estática do código fonte durante o ciclo de desenvolvimento de um software, evitando redundância de código (boilerplate), retrabalho, certificando-se que o código está dentro dos padrões de qualidade e segurança exigidos, evitando vulnerabilidade no sistema e exposição de dados sensíveis.

DevOps é relacionado à automação, a cultura devops prega a quebra dos silos e uma maior sinergia entre os times de desenvolvimento de software e operações (infraestrutura). 

Continuous Integrations (CI) é uma prática de desenvolvimento de software onde os membros de um time integram seu trabalho frequentemente, onde cada integração é verificada por um build automatizado (incluindo testes) para detectar erros de integração o mais rápido possível. É boa prática realizar commits de código o mais cedo possível ao repositório de código fonte central, para evitar retrabalho com merge e ajustes.

__Docker__

Com o Docker, é possível subir toda a aplicação dentro de um container e compartilhar com todo o time de desenvolvimento, permitindo assim, que todos os membros tenham os mesmos softwares e versões, o que elimina os problemas de compatibilidade entre versões e sistemas operacionais que normalmente ocorrem. É possível baixar um container e compartilha-lo como um arquivo de imagem (.iso), deixando todo o ambiente padronizado. Normalmente, as empresas possuem um container de Desenvolvimento, outro de Homologação e outro de Produção. Outra vantagem de se utilizar o Docker é que, caso a aplicação tenha um grande aumento no número de usuários, ele irá replicar um novo container com o sistema inteiro, ao invés de aumentar o poder de processamento da máquina servidor. Após o número de usuário diminuir, também é possível apagar o container de forma rápida.

Com o Docker, não é preciso emular um hardware ou sacrificar um processo, ou seja, ele não deixa a máquina mais lenta quando está rodando um container (ao contrário de uma Máquina Virtual). Isso ocorre pois ele não emula um hardware, mas sim, cria um processo que simula a máquina virtual hospedeira (não limita a quantidade de memória do computador hospedeiro). No Docker, você roda um container dentro na máquina hospedeira (um processo no SO na máquina hospedeira).

Baixe instala o Docker no seu computador. Para verificar se ele está rodando corretamente, abra um prompt de comando (terminal) e digite: docker run -d -p 80:80 docker/getting-started. Caso o comando der certo, o Docker vai baixar as dependências e instalar um container. Em seguida, é só acessar o site para ver o Docker rodando: http://localhost/tutorial/

O Kubernetes é utilizado para criar e destruir containers do Docker de forma automática.

Para rodar o SonarQube dentro de um container do Docker, rode o seguinte comando no terminal: docker run -d -p 9000:9000 sonarqube Agora, acesse a URL http://localhost:9000/ e faça login no sistema, para ter acesso ao SonarQube dentro do Docker

Vamos rodar agora um Sistema Operacional Linux. Primeiro, pare o container que está rodando o SonarQube (entre no Docker, procure pelo container e clique em STOP). Agora, abra o terminal e digite o seguinte comando para instalar um Linux que rode pelo browser:

docker run -p 6080:80 -v /dev/shm:/dev/shm dorowu/ubuntu-desktop-lxde-vnc
docker run -d -p 49161:1521 -e ORACLE_ALLOW_REMOTE=true -e ORACLE_ALLOW_REMOTE=true -e ORACLE_PASSWORD=oracle --name oracle-xe-11g -d -v /var/oracle-xe-11g:/u01/app/oracle epiclabs/docker-oracle-xe-11g

Para conferir se a instalação ocorreu sem problemas é só acessar a URL: http://localhost:6080

Dentro do programa Docker, se você clicar no botão CLI, será aberto um terminal de comandos (CLI) dentro do próprio programa. Nele, é possível executar diversos comandos de terminal e outros próprios do Docker.

O Portainer é uma forma gráfica de gerenciar as imagens e os containers no Docker (é o mais utilizado para SO Linux). Para instalá-lo é necessário primeiro parar o container no SobarQube (já que ele está rodando na mesma porta que o Portainer irá utilizar, que é a porta 9090) e, em seguida, rode o seguinte comando: 

docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer. 

Para conferir se a aplicação está rodando, acesse a URL http://localhost:9000 e crie uma conta. Depois, selecione a opção LOCAL e clique em CONNECT para começar a usar a aplicação.

__Integração Contínua com testes (Jenkins)__

Jenkins é uma ferramenta de integração contínua (CI) de código aberto que pode ser instalada em qualquer máquina e serve, principalmente, para executar os testes e criar os artefatos de um projeto de um software. Ele permite, por exemplo, que você gere pacotes a intervalo de tempo predeterminado, a cada commit no código ou quando você quiser. 

Job é uma atividade, ou seja, nós podemos colocar quantas ações quisermos. As ações podem ser linhas de comandos. Vamos agora criar o nosso primeiro job de teste. Dentro do ambiente Jenkins, clique em “Novo Job”, coloque o nome de “HelloWorld”, selecione a opção “Construir um projeto de software free-style” e clique em “OK”. Na próxima tela, desça até o campo de “Build” e selecione a opção “Executar no comando do Windows” (Essa janela permiti que coloquemos as mesmas linhas de comando que utilizamos no terminal do Windows). Agora escreva o comando “echo Hello!” e clique em “Salvar”. Feito isso, o job foi criado e precisamos clicar na opção “Construir agora” para executá-lo. No campo “Histórico de builds”, teremos nosso job com a bolinha azul (que indica que foi bem sucedido, caso acontecesse algum erro, a bolinha ficaria na cor vermelha) e o horário que ele foi gerado, conforme a imagem:
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dhymv8b8cctrlygs4pab.jpg)
	
Agora, vamos clicar em cima do “#1” para vermos mais detalhes da execução. Vamos clicar na opção “Saída do console”, para vermos o resultado do nosso comando. Nesta tela, está sendo exibido o nosso comando “echo Hello!” e o resultado dele na tela, que é o “Hello!”, conforme mostrado na imagem a seguir:

 ![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u6dzlpeh70x6p4pd8q3v.jpg)

__Trigger (Automação de tarefas)__

Trigger Periódica é utilizada para fazermos o “Construir agora” de forma automatizada. Para ativá-la, basta acessar as “Configurações” de uma de suas aplicações, descer até o campo de “Trigger de builds” e ativar o checkbox “Construir periodicamente”. Vai abrir um campo chamado “Agenda”, onde vamos inserir um padrão de tempo utilizando o Cron Job. Vamos adicionar neste campo “* * * * *” (cinco asteriscos, com espaço entre eles) para realizar um build a cada minuto. Por fim, basta salvar e aguardar a tarefa ser disparada.

Podemos realizar o trigger também apenas quando um evento é disparado, por exemplo, quando é realizada a alteração em algum trecho de código. Para fazer isso, vamos voltar às configurações da nossa aplicação, desmarcar a opção “Construir periodicamente” e ativar a “Consultar periodicamente o SCM”, que irá verificar o nosso GitHub que está vinculado ao projeto, verificando se houve alterações. No campo “Agenda”, vamos colocar a mesma sequência do anterior. Agora basta salvar e, quando o código for alterado, teremos o evento disparado para fazer o build novamente.

Cron é um programa de utilidade para repetir tarefas numa data futura. Cron Job é dar um comando que agenda uma tarefa, em um horário especifico, repetidamente. Ou seja, ele é um automatizador de tarefa. O Cron é um daemon, ou seja, ele trabalha em plano de fundo para executar tarefas não interativas. Um daemon está sempre no status ocioso e aguarda uma solicitação de um comando para desempenhar certa tarefa, que pode ser tanto dentro do computador principal quanto de qualquer outra máquina conectada à mesma rede. Um arquivo Cron é sempre um arquivo de texto que contém comandos para rodar em uma hora específica.

Hooks é outra forma de se fazer a automação. Ao invés do Jenkins ficar verificando o Github a cada minuto para verificar se ocorreu alguma alteração no código, com o hooks, é o Github que vai avisar para o Jenkins quando houver uma nova alteração. Ou seja, o Jenkins não precisará mais ficar monitorando o git em busca de alterações, pois ele que será avisado quando uma nova ocorrer. Para ativar esta opção, temos que selecionar o checkbox “Github hook trigger for GITScm polling” e configurá-lo segundo a documentação.

Encadeamento de Jobs ocorre quando realizamos tarefas em sequência, vamos ativar o encadeamento para fazer o deploy do back-end e, depois, deploy do front-end. Vamos entrar nas “Configurações” do projeto back-end, procurar pelo campo “Ações de pós-build” adicionar a ação de “Construir outros projetos” e no campo “Projetos para construir” vamos colocar o nome do nosso projeto front-end e, por fim, clicar em “Salvar”.

__Verificações de Qualidade__

Vamos tratar aqui sobre cinco tipos de verificações de qualidade do código: Build, Estática, Unitário, API e Funcional. O Build verifica se o código está compilando de maneira correta. A Estática vai analisar o código, verificando se existe alguma variável que foi declara e não está usada; pode verificar se existe alguma variável que não foi inicializada, mas está sendo usada; entre outras coisas. O Sonar é um software que faz a verificação estática do código. A verificação unitária vai fazer as execuções no código, propriamente dito, onde ele vai exercitar a menor porção do código (por exemplo, os métodos) e nós vamos criar diversos cenários para ver como o método se comporta sob parâmetros distintos. Uma vez que estejamos cobrindo todos os métodos sobre todos os parâmetros possíveis, teremos uma grande chance de não termos problemas quando integrarmos. A verificação de API (testes de serviços) vai testar os serviços propriamente ditos. Para fazer estas verificações, vamos colocar o serviço no ar, deixando a API exposta e, então, vamos realizar testes diretamente nesta API, utilizando o REST Assured para isso. Após esta etapa, poderemos fazer o deploy do front-end e fazer os testes da aplicação como um todo (verificação funcional), em nível da interface do usuário. 

Os testes unitários são baratos, rápidos de fazer e devem existir em um número muito maior que os testes de serviços e interface. Os testes de serviço são mais caros e mais lentos que os testes unitários, e devem existir em um número maior que os testes de interface, mas menor que os testes unitários. Por fim, os testes de interface do usuário, são testes caros e lentos, por isso devem existir em números muito menores que os demais tipos. 

__SonarQube__

SonarQube é uma ferramenta para garantir a qualidade do código fonte em desenvolvimento, realizando diversas análises durante o processo de compilação da aplicação, verificando a segurança, trecho de código fonte que possam gerar bugs, duplicidade de linha de comando, etc.

__Integrando SonarQube com o Jenkins__

Depois de configurar o Sonar no Docker, acesse o site do Sonar no ambiente local, faça login (usuário e senha padrão é admin), entre em “My Account”, depois vá em “Security” e gere um novo token, com o nome de “jenkins” e clique em “Generate”. Agora, copie o token gerado, volte no Jenkins para adicionar os novos plug-ins, clique em “Gerenciar Jenkins”, depois em “Gerenciar Plugins”, vá até a aba “Disponíveis” e procure por “SonarQubeScanner” e “Sonar Quality Gates” e instale ambos.

Volte para a aba de “Gerenciar Jenkins”, clique em “Configurar o sistema”, procure pelo SonarQube e clique em “Add Sonar”. Coloque o nome “SONAR_LOCAL”, coloque na url o endereço do SonarQube do Docker e adicione o token de autenticação, colando o token que foi gerado lá no SonarQube. Clique em salvar e desça até o Quality Gates, coloque o nome como “SOLAR_LOCAL_QG”, insira o mesmo endereço do Sonar em URL, adicione o token novamente e clique em Salvar.

Volte em “Gerenciar Jenkins”, clique em “Global Tool Configuration”, procure por “SonarQube Scanner”, coloque o nome “SONAR_SCANNER” e deixe a opção “instalar automaticamente” como selecionada. Por fim, é só Salvar.

__Analisando código com Sonar__

Dentro do Sonar, clique em “Create new Project” e coloque o nome do projeto de “DeployBack”, em seguida, coloque o nome do token como “scanner” e clique em Generate. Depois, escolha o tipo de projeto como “Java” e o build como “Maven”, copie o código gerado, que é similar à do exemplo:

mvn sonar:sonar -Dsonar.projectKey=guilherme -Dsonar.host.url=http://157.245.241.135:9000 -Dsonar.login=1106c7737f25d8ef76d2cfac412eece450c8ffa0

Volte para o Jenkins, entre dentro do projeto “DeployBack”, em “Configurações” procure por “Build”, clique na opção “Adicionar passo no build” e escolha “Execute SonarQube Scanner” e em “Analysis properties”, cole o código gerado no Sonar sem copiar o comando “mvn sonar: sonar”, retirando o “-D” e “/” presentes no código e adicionando o trecho de código “sonar.java.binaries=target” (target é a pasta onde estão os binários do nosso projeto). Agora, clique em “Salvar” e clique na opção “Construir agora”, para fazer o build do projeto.

Volte para a tela do Sonar e clique em “Projects”, será exibido uma lista com todos os seus projetos e a quantidade de bugs, vulnerabilidades, code smells, entre outros.

__Quality Gate__

São regras que podemos criar dentro do Sonar, para dizer se o teste (projeto) passou ou não, baseado nos parâmetros que foram definidos. Para criar uma nova regra, vá na aba “Quality Gates”, clique em “Create” e insira um nome. Depois, clique em “Add Condition” para adicionar um novo parâmetro nas regras.

Para adicionar o Quality Gate no processo, vamos ir no projeto “DeployBack” no Jenkins, em “Configurar”, vamos adicionar uma nova ação no pós-build chamada de “Quality Gates Sonarqube Plugin”, colocar o nome do projeto (igual ao que está no Sonar) e clicar em “Salvar”. Por fim, basta fazer uma nova construção do projeto, para o teste passar primeiro pelo Sonar para depois criar o build.

__Testes Unitários (JUnit)__

O teste é dividido basicamente em três etapas: cenário, que é onde as variáveis serão inicializadas; ação, que é aonde vamos invocar o método que queremos testar; e a validação, que é onde vamos coletar o resultado da ação com aquele cenário especificado e podemos avaliar se o resultado está de acordo com o esperado. 
 	
Um teste precisa seguir o princípio do FIRST (Fast, Independent, Repeatable, Self-Verifying e Timely). Fast significa que um teste unitário deve ser executado muito rápido; independent significa que um teste não deve depender de outros, podendo inclusive, rodar em qualquer ordem; repeatable significa que um teste pode ser executado quantas vezes quiser e na hora que quiser, retornando sempre o mesmo resultado; self-verifying significa que um teste deve saber quando a sua execução foi correta ou quando ela falhou; timely significa que o teste precisa ser criado no momento correto (oportuno).

xUnit é o nome genérico para qualquer estrutura de testes automáticos unitários. Alguns dos pontos que este padrão deve definir são: TestRunner (quem vai fazer o teste e coletar os resultados), TestFixture (são as pré-condições necessárias para o teste), TestSuites (é onde eu posso elencar onde os testes vão ser executados), TestResultFormatter (que é quem vai padronizar os resultados dos testes) e as Assertions (verifica o comportamento ou o estado do que está sendo testado, geralmente através de uma expressão lógica. Caso uma sessão não for satisfeita, o teste será parado neste momento). Este padrão foi criado visando os testes unitários, mas sua estrutura pode ser usada perfeitamente para outros tipos de testes, como os testes de integração, testes funcionais, etc.

O JUnit são os testes unitários do Spring e servem para testar a lógica do programa. Para ativá-lo no Spring, insira as seguintes dependências no arquivo pom.xml (Maven):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/q2nzfek0u59a4yp6zfh1.jpg)

Agora, crie um novo pacote com o nome de br.com.projeto.util e, dentro dele, uma classe chamada MathUtil. Em seguida, vá até a pasta src/test/java e crie um novo pacote chamado de util. Clique no pacote com o botão direito do mouse -> new -> other -> JUnit test case -> colocar nome da classe igual ao do pacote principal (MathUtilTest). Agora, faça a injeção de dependência do MathUtil e coloque a função para testar a lógica matemática, conforme visto a seguir:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/twe9cxwdf9pwqykv20gi.jpg)

Para testar a classe, clique em Run As -> JUnit Test. Caso retorne uma barra verde na tela dos testes, significa que ele passou sem problema, e caso apareça uma barra vermelha, significa que ocorreu algum erro durante o teste.

Agora, se você alterar o conteúdo da linha 10 por: int esperado = 4; e rodar o teste novamente, o teste vai gerar um erro dizendo que o valor esperado não é 4, mas sim 3. A mensagem de erro será: org.opentest4j.AssertionFailedError: expected: <4> but was: <3>

Crie agora um novo pacote com o nome de br.com.projeto.controller (em test) e, dentro dele, crie uma nova classe chamada de CategoriaControllerTest. Dentro desta classe, insira o seguinte código:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7lijjpm9ta1vpxv5as8x.jpg)

A anotação @SpringBootTest sinaliza que criamos uma classe de teste no Spring. O ObjectMapper é utilizado para ler o que está dentro de uma String e converte-lo para um objeto do tipo JSON (no caso, de categoria). Na linha 26, é necessário inserir o TOKEN de login, conforme o exemplo:

....get("/categorias/1").contentType("application/json").header("Authorization", "Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c3VhcmlvQHVzdWFyaW8uY29tIiwic2NvcGVzIjoiUk9MRV9BRE1JTixST0xFX0NMSUVOVEUiLCJub21lIjoiVXN1w6FyaW8gMiIsImlkIjoxLCJpYXQiOjE2MDM4MjM4ODMsImV4cCI6MTYwMzgyNzQ4M30.O1oBotxIZp3hYAtxGrvTLuy40y2IE-3WreUTmExMssiLUWs9gOvr63b2wPpWk-3fOXR24j3YXzDDyWtvDK0DSw"));

A anotação @BeforeEach realiza uma determinada operação antes do teste ser iniciado.

__Assertivas__

Assertivas é uma das características dos frameworks xUnit e está diretamente relacionada a uma expressão lógica. Se a expressão lógica for verdadeira, o teste segue o caminho dele, do contrário, o teste irá falhar naquele ponto (por padrão). Algumas funcionalidades do Assert (do import org.jnuit.Assert) são:

•Assert.assertTrue(true) = testa se a expressão for verdadeira;
•Assert.assertFalse(false) = testa se a expressão for falsa;
•Assert.assertEquals(1, 1) = testa se um valor é igual a outro, mas possui variação de método para cada tipo diferente de dados (double, long, float, String, etc). No caso da comparação de valores que tenham casas decimais, este método exige que a função possua um delta de comparação (margem de erro). Um exemplo seria Assert.assertEquals(0.51, 0.51, 0.01), onde a variação entre os dois números poderá ser de até 0.01, para mais ou para menos. É importante usar o delta de comparação para que possamos comparar, por exemplo, números que possuam dízimas periódicas infinitas (como o PI). Todos os tipos primitivos possuem uma representação em forma de objeto, conhecidos como classes Wrappers. Por exemplo, o int pode ser representando como tipo primitivo (int i = 5) ou representado como objeto (Integer i2 = 5). Para comparar um tipo primitivo e uma classe Wrapper, é preciso converter um deles, pois só é possível comparar variáveis de tipos iguais. Para fazer a comparação entre dois tipos de objetos, é necessário que eles possuam os métodos equals implementado;
•Assert.assertTrue("bola".equalsIgnoreCase("Bola")) = testa se duas Strings são iguais, ignorando o case sensitive (letras maiúsculas e minúsculas);
•Assert.assertTrue("bola".startsWith("bo")) = testa duas Strings, ignorando o seu radical;
•Assert.assertSame(u1, u2) = testa se dois objetos são da mesma instância;
•Assert.assertNull(u3) = testa se o objeto está vazio;
•Assert.assertNotNull(u3) = testa se o objeto não está vazio;
•Assert.assertNotEquals() = testa se dois objetos são diferentes;
•Assert.assertNotSame(u1, u2) = testa se dois objetos são iguais, porém de instâncias diferentes;
•Assert.assertEquals("Erro de comparação", 1, 2) = é possível colocar uma String, testa se dois objetos são iguais.
•AssertThat... = significa verifique que. Há dois motivos para se utiliza-lo: é possível fazer qualquer verificação que quiser, pois existe uma biblioteca de assertivas para se utilizar e dá até para criar as nossas próprias bibliotecas; além de, também, deixar a leitura do método mais fluido;
•Assert.assertThat(locacao.getValor(), CoreMatchers.is(5.0)) = verifica se o valor da locação é igual a 5.0;
•Assert.assertThat(DataUtils.isMesmaData(locacao.getDataRetorno(), DataUtils.obterDataComDiferencaDias(1)), is(true)) = este método verifica se duas datas são iguais;
•Assert.fail("Deveria ter lançado uma exceção") = lança uma exceção que exibe os valores reais e esperados separados pelo operador fornecido;

__Forma para se dividir um teste unitário__

A anotação @Rule permite alterar alguns comportamentos do teste, além de ser também possível alterar criar regras próprias com eles. Vamos utilizar, por exemplo, o ErrorCollector e trocar nossas três linhas de código pelas seguintes:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ana1u16agilulrtcm0bl.jpg)

Agora, quando rodar novamente o teste, é possível ver o resultado de cada um deles separadamente, mesmo que um deles falhe no meio do caminho.

Tratamento de Exceções em Testes
Falhas ocorrem quando um teste é executado sem problemas, porém, alguma condição que era esperada não foi atendida. Já um erro acontece quando algum problema durante a execução de testes impede que o mesmo seja concluído (ou seja, quando ocorre uma exceção não esperada e não tratada). 

Se o teste não está esperando exceção nenhuma, deixe que o JUnit gerencie ele por você. Vejamos um exemplo disso na prática, vou criar uma condição de erro que possa gerar uma exceção em uma classe:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tmqgo15h9q2jwvmha8mk.jpg)

Agora, é só adicionar o throws Exception na nossa classe teste, que ficará assim: 
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/84oe4snok8luvcl51rdb.jpg)

Mas, se o teste estiver esperando uma exceção, temos que executar o teste de outra maneira. Por exemplo, vamos testar se um filme não está em estoque (ou seja, para o teste passar, uma exceção terá que ser lançada). 

Existem três formas para se tratar uma exceção enviada. A primeira forma, que pode ser chamada de solução elegante, que vai apenas lançar a exceção com o mesmo nome daquela da nossa classe principal. Ela é uma forma muito simples e enxuta, porém, superficial. Como essa forma não exibe a mensagem de erro, só é recomendado de se utilizar quando um projeto tenha uma exceção que possa ser causada apenas por um determinado motivo, conforme o exemplo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fq4ecpix0wyrj4gjp2if.jpg)

A segunda forma, que pode ser chamada de robusta, permite um controle maior sobre a execução do teste do que a anterior. A vantagem dessa forma é que, além de capturar a exceção, também podemos capturar verificar a mensagem que vem da exceção. Ela é recomendada para se utilizar nos casos em que há uma exceção mais genérica no código e todas as exceções que ocorrem no projeto, seguram dentro de um try/catch e a lançam diretamente na classe alvo. Vamos a um exemplo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7chn3t498tch1sjkpsig.jpg)

A terceira forma é mais nova, vamos começar declarando uma nova Rule para podermos utilizá-la e criar nossa classe de teste:
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kzrtams7fdimh7ewsdru.jpg)

A segunda e terceira forma consegue tratar exceção tratada e lançada, a diferença entre elas é que, a forma robusta é a que podemos ter o maior poder sobre a execução do teste, já que ela segura a exceção no bloco try/catch e continua o fluxo do teste mesmo após lançar a exceção. Já na terceira forma, ela está lançando para que o JUnit faça os tratamentos porém, ela está avisando ao JUnit o que está esperando e é por isso que o JUnit segura a mensagem e não coloca nem erro nem falha.

__Anotações em Teste__
A anotação @Before permite executar um trecho de código antes de rodar os testes. A anotação @After permite executar um trecho de código após rodar os testes.

A anotação @FixMethodOrder(MethodSorters.NAME_ASCENDING) executa os testes por ordem alfabética.

A anotação @Ignore ignora um teste de ser executado, é altamente recomendável utilizá-la quando queremos manter algum teste em stand-by. Já o método Assume.assumeTrue(DataUtils.verificarDiaSemana(new Date(), Calendar.SATURDAY)) é utilizado quando queremos que um teste seja executado apenas em um data específica, como no Sábado, conforme o exemplo. Se NÃO quisermos que o teste rode apenas em uma data específica, podemos utilizar o método Assume.assumeFalse(). A utilização destes métodos é muito útil quando um teste precisa de um determinado recurso, ou seja, antes de executar o teste, podemos verificar se este recurso está ou não disponível.

__Testes Parametrizados__

Estes tipos de testes são utilizados quando queremos passar diferentes parâmetros para um mesmo cenário de teste e observar se o comportamento é o esperado. Para rodar os testes parametrizados, precisamos primeiro adicionar a anotação @RunWith(Parametrized.class) em cima do nome da classe. A anotação @Parameter indica os campos que serão os parâmetros da classe (vai receber os valores). Os métodos que definem a coleção precisam ser do tipo static, pois é ele que quem vai definir a quantidade de execuções de cada método de teste. Vejamos um exemplo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pe3pvwugj9svrf798fir.jpg)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uagni8iza5ba63ijs80v.jpg)

__Testes de API (REST Assured)__
Vamos criar uma classe para fazermos a primeira requisição na nossa API, fazendo um teste, conforme código abaixo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mc4ptfzzeyjrbz4ip9ft.jpg)

No parâmetro given nos informamos algumas pré condições, when é quando executamos determinada ação e then ele começa a fazer as assertivas. Vamos retornar o status 400 para as tarefas.

__Testes Funcionais (Selenium)__

Selenium é uma ferramenta que automatiza execuções no browser, ou seja, se utilizarmos ele com algum framework de testes, como o JUnit, podemos criar expectativas e, através do Selenium, fazer navegações na aplicação para ver se ela está se comportando como deveria. Vamos criar um exemplo:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/eeuztkkir5137lin1bvy.jpg)

Selenium Grid é um hub que nos permite centralizar, paralelizar e distribuir nossos testes em nós que nele são registrados. Quando for disparado uma execução de testes a partir da máquina local, será feito uma requisição a um servidor (selenium grid) e este servidor conhece várias máquinas que estão conectadas e ele (chamada de nós), e toda requisição que este servidor receber, ele vai distribuí-las entre os nós.

__Test Driven Development (TDD)__

TDD (Desenvolvimento Guiado por Testes) é uma metodologia onde vamos primeiro criar o teste, depois criamos o código e por fim iremos refatorá-lo. Esse código terá o mínimo necessário para que o teste passe e, depois que tudo estiver funcionando, aplicaremos a refatoração do código com segurança (caso haja necessidade).

__Teste de Cobertura (Total)__

O teste de cobertura é utilizado para testar todo o código, e não apenas uma classe ou parte do código. Vamos baxar e instalar o eclEmma para criarmos um teste de cobertura total. 

Após isso, entre no projeto Spring -> clique em Help -> Install new software -> clicar no botão Add -> Botão Archive... -> Selecionar o arquivo eclemma.zip -> Finish (Instalar o programa). Clique com o botão direito em qualquer classe e tem que aparecer a opção: Covegare As...  Por fim, escolha a opção JUnitTest e o teste de cobertura será executado, exibindo na tela a porcentagem de código coberta pelo teste, grifando em verde as áreas do código que estão cobertas pelo teste.