• Nenhum resultado encontrado

UMC - Testes de Software - 6 - TDD - A

N/A
N/A
Protected

Academic year: 2021

Share "UMC - Testes de Software - 6 - TDD - A"

Copied!
47
0
0

Texto

(1)

Testes de Software –

Parte 2 - TDD

UMC

(2)

Introdução

• Desde o nascimento da era do computador, programadores e bugs tem batalhado por supremacia. É uma ocorrência inevitável.

• Mesmo o maior dos programadores falha a essas anomalias. Nenhum código é seguro.

• Isto é porque testamos. Programadores, pelo menos os sãos, testam seus códigos os executando em suas máquinas de desenvolvimento para ter certeza de que eles fazem o que é suposto fazerem.

Programador são que testa seus programas

(3)

TDD

• O TDD (Test Driven Development / Desenvolvimento orientado a teste) é parte da metodologia XP e também utilizado em diversas outras metodologias, além de poder ser utilizada livremente.

• O TDD transforma o desenvolvimento, pois deve-se primeiro escrever os testes, antes de implementar o sistema.

• No TDD é indicado que o projeto de teste unitário ocorra antes da fase de codificação/implementação.

• Neste caso o desenvolvedor, para implementar os testes iniciais, deve compreender com detalhes a especificação do sistema e as regras de negócio, só assim, será possível escrever testes para o sistema.

• Uma das vantagens de possuir testes é a chamada regressão. Imagine que criamos os testes, fizemos o sistema e tudo foi entregue ao cliente, mas posteriormente o cliente pediu pequenas modificações no sistema, mas não nas regras de negócio. Os testes já prontos servirão para validar se as modificações não criaram problemas nas regras de negócio que já estavam em funcionamento. Este procedimento exige que testes

(4)

TDD

• As tradicionais metodologias de desenvolvimento de software incorporam um longo ciclo de vida na codificação, teste e produção.

• Mas o desenvolvimento dirigido a testes (DDT) é um novo processo de

desenvolvimento de software que muda o processo tradicional por promover a escrita de testes antes de escrever um código funcional.

• O desenvolvimento dirigido a testes é um dos principais componentes da Extreme Programming.

• Kent Beck, considerado o criador ou o 'descobridor' da técnica, declarou em 2003 que TDD encoraja designs de código simples e inspira confiança.

• Desenvolvimento dirigido por testes é relacionado a conceitos de

programação de Extreme Programming, iniciado em 1999, mas recentemente tem-se criado maior interesse pela mesma em função de seus próprios ideais. • Através de TDD, programadores podem aplicar o conceito de melhorar

(5)

TDD

(6)

TDD

• O processo envolve:

– primeiro escrever um teste e ter certeza que ele irá falhar.

– o segundo passo, você escreve apenas código suficiente para que o teste passe.

– então você roda o teste novamente para ter certeza que o teste passe. – se falhar, significa que há um problema com o código funcional e você

precisa atualizar o código funcional para que o teste passe.

– uma vez terminado este pequeno teste, você começa novamente com um teste diferente.

(7)

TDD - Como funciona o processo?

• Para cada funcionalidade: • 1. Faça o Design:

– faça o projeto para poder entender como será a funcionalidade a ser implementada. – pode ser feito numa folha de papel, ou no código mesmo através de comentários.

– coloque na folha de papel todos os estados que precisarão ser testados pelo método de teste e não se esqueça¸ um bom teste não se mede pela quantidade de linhas de código que ele irá percorrer, mais sim, pela quantidade de estados possíveis que ele irá testar.

/**

* Método de teste para o método soma da classe SomaValores. */

public static void testeSoma() {

//a fazer: testar com um valor positivo e negativo //a fazer: testar com um valor negativo e positivo //a fazer: testar dois valores positivos

(8)

TDD - Como funciona o processo?

• 2. Crie um teste:

– escreva o método de teste de acordo com os estados projetados no passo anterior (Design) que testarão o método que ainda não foi implementado.

– Obs. o código ainda não irá compilar.

/**

* Método de teste para a classe soma da classe SomaValores. */

public static void testeSoma() { int retorno;

//testar com um valor positivo e negativo retorno = SomaValores.soma(2, -3);

assertEquals("Valor esperado: -1, valor retornado: "+retorno, -1, retorno);

//a fazer: testar com um valor negativo e positivo //a fazer: testar dois valores positivos

(9)

TDD - Como funciona o processo?

• 3. Faça o código compilar:

– crie o método apenas para o código compilar, não o implemente ainda.

public class SomaValores {

/**

* Método que retorna a soma dos valores passados por *parâmetro. * @param i

* @param j */

public static int soma(int i, int j) {

// a fazer: Auto-generated method stub

return 0;

} }

(10)

TDD - Como funciona o processo?

• 4. Execute o teste:

– rode o teste que ainda não irá passar, pois o método não foi implementado até o momento.

• 5. Implemente o método:

– implemente o método contendo a funcionalidade requerida para passar no teste criado no passo 2, sem se preocupar em torná-lo elegante/otimizado.

– É extremamente importante que o método implementado contenha somente o que é necessário para passar no teste.

(11)

TDD - Como funciona o processo?

public class SomaValores { /**

* Método que retorna a soma dos valores passados por parâmetro. *

* @param i * @param j */

public static int soma(int i, int j) { return i+j;

} }

(12)

TDD - Como funciona o processo?

• 6. Execute novamente o teste:

– se todos os testes passarem, você terá certeza que o código atende todos os requisitos testados e que esta nova funcionalidade não afetou outras partes do sistema.

• 7. Refatore o código:

– agora você pode "limpar" o código, se for necessário.

– lembrar de executar os testes constantemente durante esta etapa, pois só assim você saberá se o sistema não foi modificado de maneira incorreta, gerando erros.

(13)

TDD

• EXEMPLO:

• Dado o chassi de um veículo, como, por exemplo, 9BP17164GA0000001, será necessário identificar qual o ano de fabricação deste veículo.

• Todo chassi possui um caractere alfa numérico (letra ou número) que possui esta informação.

• Neste exemplo de chassi, o caractere ‘A’ na 10º posição informa que o veículo é do ano 2010.

• A tabela abaixo possui alguns valores e os anos que eles representam:

 Valor Ano 

A 2010

B 2011

(14)

TDD

• Antes de começar essa funcionalidade, precisamos pensar quais testes gostaríamos de fazer para que essa funcionalidade seja executada da melhor forma possível?

• Poderíamos testar, por exemplo:

– Testar se o chassi com o valor A retorna o ano 2010. – Testar se o chassi com o valor B retorna o ano 2011. – Testar se o chassi com o valor C retorna o ano 2012.

– Testar se um chassi pode ser escrito com caracteres em maiúsculo ou minúsculo.

– Testar se um chassi incompleto retorna um erro de informação inválida

(15)

TDD

• Durante a implementação dos testes, novas dúvidas podem surgir e nada impede que sejam adicionados mais testes a essa lista inicial de testes. • Primeiro será necessário criar um teste de algo que ainda não foi

implementado. Mas o que testar, se nada existe?

• Dado o problema, sabemos que, ao informar o chassi

9BP17164GA0000001 e a posição 10, é esperado que a aplicação informe que o ano desse chassi é 2010.

• Portanto podemos criar uma classe contendo um teste que espera que isso aconteça.

(16)

TDD

• Exemplo usando o JUNIT (versão 4): • Criar a classe ChassiUtilTest

package tdd.chassi.util; import org.junit.Test;

import static org.junit.Assert.*; public class ChassiUtilTest { @Test

public void testarAnoAChassi() {

ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9BP17164GA0000001", 10)); }

(17)

TDD

• Foi criada uma classe chamada ChassiUtilTest para realizar todos os testes.

• Nela criamos um método chamado testarAnoAChassi() que será utilizado para testar.

• Se o valor da posição do ano no chassi for A será informado que o ano do chassi é 2010.

• Neste primeiro momento, a classe ChassiUtilTest não irá nem compilar, porque a classe ChassiUtil não existe portanto, ao executar os testes dessa classe, teremos a seguinte saída do JUnit:

(18)

TDD

• Agora precisamos implementar apenas o suficiente para que o teste funcione.

• Crie a classe ChassiUtil que irá implementar o método obterAno(String chassi, int posicaoAno) retornando apenas o valor 2010.

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) { return 2010;

} }

(19)

TDD

• Foi criada uma implementação com o suficiente para que o teste funcione. Agora ao executar o teste, teremos a seguinte saída do Junit:

(20)

TDD

• Note que normalmente utilizamos o mesmo pacote para colocar a classe Java na implementação e na classe de teste.

• Como a implementação ainda é bem simples, podemos agora refatorar este método para implementa-lo de uma maneira melhor, como, por exemplo, verificar se o caractere na posição recebida como parâmetro tem o valor igual a ‘A’:

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) {

/* Como os caracteres começam na posição zero, é necessário subtrair 1 da posição do ano informada. */

if(chassi.charAt(posicaoAno - 1) == 'A') return 2010;

return 0; }

(21)

TDD

• Agora que foi alterada a implementação, é necessário testar novamente para verificar se a alteração não irá causar a falha dos testes:

(22)

TDD

• Agora que o teste está funcionando e implementamos o mínimo

necessário para ele funcionar, precisamos pensar em o que mais pode ser testado, como, por exemplo:

– se o chassi for informado com os caracteres em minúsculo 9bp17164ga0000001. Será que ele irá funcionar?

• Adicione mais um teste na classe ChassiUtilTest, chamado

testarAnoAMinusculoChassi() para testar se um chassi que possui os caracteres em minúsculo também irá retornar o ano corretamente.

• Observação: note que definimos os nomes dos testes bem informativos e específicos com o que será testado

(23)

TDD

package tdd.chassi.util;

import org.junit.Test;

import static org.junit.Assert.*; public class ChassiUtilTest { @Test

public void testarAnoAChassi() { ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9BP17164GA0000001", 10)); }

@Test

public void testarAnoAMinusculoChassi() { ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9bp17164ga0000001", 10));

}

(24)

TDD

• Vamos executar novamente os testes da classe ChassiUtilTeste:

• Ao executar os testes da classe ChassiUtilTest agora temos um erro no teste testarAnoAMinusculoChassi.

• Já havíamos refatorado a classe ChassiUtil e, mesmo assim, porque os testes não funcionam? A implementação do que está sendo testado cobre apenas o necessário para que os testes existentes funcionem, mas, conforme novos testes vão sendo adicionados, pode ocorrer que a implementação atual não trate uma determinada situação.

(25)

TDD

• Vamos refatorar novamente a classe ChassiUtil para que os dois testes

atuais funcionem. Para isso, podemos apenas sempre converter o texto do chassi para maiúsculo antes de verificar o valor do caractere.

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) {

/* Como os caracteres começam na posição zero, é necessário subtrair 1 da posição do ano informada. */

if(chassi.toUpperCase().charAt(posicaoAno - 1) == 'A') return 2010;

return 0; }

(26)

TDD

(27)

TDD

• Agora continuando os testes, precisamos testar se o chassi que possui o caractere 'B' tem o ano 2011. Então, vamos criar mais um teste:

package tdd.chassi.util; import org.junit.Test;

import static org.junit.Assert.*; public class ChassiUtilTest {

@Test

public void testarAnoAChassi() { ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9BP17164GA0000001", 10)); }

@Test

public void testarAnoAMinusculoChassi() { ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9bp17164ga0000001", 10)); }

(28)

TDD

@Test

public void testarAnoBChassi() {

ChassiUtil util = new ChassiUtil();

assertEquals(2011, util.obterAno("9BP17164GB0000001", 10)); }

(29)

TDD

• O método chamado testarAnoBChassi() foi utilizado para testar se o valor da posição do ano no chassi 9BP17164GB0000001 será informado que o ano do chassi é 2011.

• Ao testar novamente esta classe teremos a seguinte saída:

• O teste falhou porque ainda não foi implementado, portanto vamos

implementar uma condição que quando o caractere da posição informada for igual a 'B' deve retornar o ano 2011.

(30)

TDD

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) {

/* Como os caracteres começam na posição zero, é necessário subtrair 1 da posição do ano informada. */

if(chassi.toUpperCase().charAt(posicaoAno - 1) == 'A') return 2010; else if(chassi.toUpperCase().charAt(posicaoAno - 1) == 'B') return 2011; return 0; }

(31)

TDD

• Agora que criamos uma implementação podemos testar novamente para verificar se todos os testes ainda estão funcionando.

(32)

TDD

• Continuando a implementação, precisamos testar se o chassi que possui o caractere 'C' tem o ano 2012.

• Então vamos criar mais um teste: package tdd.chassi.util;

import org.junit.Test;

import static org.junit.Assert.*; public class ChassiUtilTest {

@Test

public void testarAnoAChassi() { ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9BP17164GA0000001", 10)); }

@Test

public void testarAnoAMinusculoChassi() { ChassiUtil util = new ChassiUtil();

assertEquals(2010, util.obterAno("9bp17164ga0000001", 10)); }

(33)

TDD

@Test

public void testarAnoBChassi() {

ChassiUtil util = new ChassiUtil();

assertEquals(2011, util.obterAno("9BP17164GB0000001", 10)); }

@Test

public void testarAnoCChassi() {

ChassiUtil util = new ChassiUtil();

assertEquals(2012, util.obterAno("9BP17164GC0000001", 10)); }

(34)

TDD

• O método chamado testarAnoCChassi() foi utilizado para testar se o valor da posição do ano no chassi 9BP17164GC0000001 será informado que o ano do chassi é 2012.

• Note que em todos os métodos criamos um objeto da classe ChassiUtil chamado util, para poder testar os métodos que ele possui.

• O JUnit possui uma anotação chamada @Before que é adicionado a um método para ser executado antes que comece a execução dos testes e uma anotação chamada @After que é adicionado a um método para ser executado após a execução de todos os métodos.

• Então, podemos alterar a classe de teste para criar o objeto da classe ChassiUtil antes de iniciar os testes, ao invés de ficar criando um objeto em cada teste.

(35)

TDD

package tdd.chassi.util; import org.junit.Before; import org.junit.Test;

import static org.junit.Assert.*; public class ChassiUtilTest {

private ChassiUtil util = null; @Before

public void inicializar() { util = new ChassiUtil();

}

@Test

public void testarAnoAChassi() {

assertEquals(2010, util.obterAno("9BP17164GA0000001", 10)); }

(36)

TDD

@Test

public void testarAnoAMinusculoChassi() {

assertEquals(2010, util.obterAno("9bp17164ga0000001", 10)); }

@Test

public void testarAnoBChassi() {

assertEquals(2011, util.obterAno("9BP17164GB0000001", 10)); }

@Test

public void testarAnoCChassi() {

assertEquals(2012, util.obterAno("9BP17164GC0000001", 10)); }

(37)

TDD

• Ao testar novamente esta classe teremos a seguinte saída:

• O teste falhou porque ainda não foi implementado, portanto vamos

implementar uma condição que quando o caractere da posição informada for igual a 'C' deve retornar o ano 2012.

(38)

TDD

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) {

/* Como os caracteres começam na posição zero, é necessário subtrair 1 da posição do ano informada. */

if(chassi.toUpperCase().charAt(posicaoAno - 1) == 'A') return 2010; else if(chassi.toUpperCase().charAt(posicaoAno - 1) == 'B') return 2011; else if(chassi.toUpperCase().charAt(posicaoAno - 1) == 'C') return 2012; return 0; } }

(39)

TDD

• Vamos executar novamente os testes para verificar se agora o teste vai funcionar:

(40)

TDD

• Note que as últimas implementações foram uma cópia da implementação do primeiro teste, apenas alterando o valor do caractere e o retorno.

• Vamos refatorar esta classe.

• Ao invés de utilizarmos diversos testes, vamos calcular o ano baseado no caractere.

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) {

/* Como os caracteres começam na posição zero, é necessário subtrair 1 da posição do ano informada. */

char caractere = chassi.toUpperCase().charAt(posicaoAno - 1); return (caractere - 'A') + 2010;

} }

(41)

TDD

• Vamos adicionar mais um teste que espera obter uma exceção quando um chassi inválido for informado.

package tdd.chassi.util; import org.junit.Before; import org.junit.Test;

import static org.junit.Assert.*; public class ChassiUtilTest { private ChassiUtil util = null; @Before

public void inicializar() { util = new ChassiUtil(); }

@Test

public void testarAnoAChassi() {

assertEquals(2010, util.obterAno("9BP17164GA0000001", 10)); }

(42)

TDD

@Test

public void testarAnoAMinusculoChassi() {

assertEquals(2010, util.obterAno("9bp17164ga0000001", 10)); }

@Test

public void testarAnoBChassi() {

assertEquals(2011, util.obterAno("9BP17164GB0000001", 10)); }

@Test

public void testarAnoCChassi() {

assertEquals(2012, util.obterAno("9BP17164GC0000001", 10)); }

@Test(expected=IllegalArgumentException.class)

public void testarExcecaoDeChassiInvalido() { util.obterAno("teste", 10);

} }

(43)

TDD

• O método testarExcecaoDeChassiInvalido() valida se o método obterAno recebendo um chassi inválido como, por exemplo, o valor “teste”, lança uma exceção do tipo IllegalArgumentException (exceção de argumento inválido ou ilegal), para tratar que esperamos esta exceção, adicionamos na anotação @Test a propriedade expected, que recebe como parâmetro a classe da exceção que será lançada.

(44)

TDD

• O teste mostra que era esperado a exceção IllegalArgumentException, mas o método lançou o erro

StringIndexOutOfBoundException, porque não tratamos na implementação os textos de chassi

inválidos.

• Vamos alterar a implementação para validar se o chassi possui um tamanho mínimo de 17 caracteres:

package tdd.chassi.util; public class ChassiUtil {

public int obterAno(String chassi, int posicaoAno) {

if(chassi == null || chassi.trim().length() < 17) {

throw new IllegalArgumentException("O chassi informado é inválido!"); }

/* Como os caracteres começam na posição zero, é necessário subtrair 1 da posição do ano informada. */

char caractere = chassi.toUpperCase().charAt(posicaoAno - 1); return (caractere - 'A') + 2010;

} }

(45)

TDD

• Agora que validamos se o chassi informado é nulo ou possui um tamanho menor que 17 caracteres será lançada uma exceção

IllegalArgumentException, para informar que o chassi é inválido. Vamos executar novamente os testes:

(46)

TDD

• O caractere 'A' equivale ao número 65, o caractere 'B' equivale ao número 66 e assim por diante portanto, ao subtrair o caractere do chassi por 'A', teremos o valor que deve ser adicionado com 2010 para encontrar o ano informado.

• Vamos testar novamente para verificar se após estas alterações os testes continuarão a funcionar:

(47)

Referências

Documentos relacionados

Através do experimento in vivo, verificou-se que o pó nebulizado de nanocápsulas (Neb-NC) é efetivo na proteção da mucosa gastrintestinal frente à indometacina, enquanto que os

As pontas de contato retas e retificadas em paralelo ajustam o micrômetro mais rápida e precisamente do que as pontas de contato esféricas encontradas em micrômetros disponíveis

a) Aplicação das provas objetivas. b) Divulgação dos gabaritos oficiais do Concurso Público. c) Listas de resultados do Concurso Público. Os recursos interpostos que não se

Foi apresentada, pelo Ademar, a documentação encaminhada pelo APL ao INMETRO, o qual argumentar sobre a PORTARIA Nº 398, DE 31 DE JULHO DE 2012 E SEU REGULAMENTO TÉCNICO

Neste trabalho avaliamos as respostas de duas espécies de aranhas errantes do gênero Ctenus às pistas químicas de presas e predadores e ao tipo de solo (arenoso ou

O valor da reputação dos pseudônimos é igual a 0,8 devido aos fal- sos positivos do mecanismo auxiliar, que acabam por fazer com que a reputação mesmo dos usuários que enviam

5.2 Importante, então, salientar que a Egrégia Comissão Disciplinar, por maioria, considerou pela aplicação de penalidade disciplinar em desfavor do supramencionado Chefe

Box-plot dos valores de nitrogênio orgânico, íon amônio, nitrito e nitrato obtidos para os pontos P1(cinquenta metros a montante do ponto de descarga), P2 (descarga do