• Nenhum resultado encontrado

aula03 projetoSistemas JUnit 2012.2

N/A
N/A
Protected

Academic year: 2021

Share "aula03 projetoSistemas JUnit 2012.2"

Copied!
23
0
0

Texto

(1)

Testes de Unidade com JUnit

Projeto de Sistemas

Roberto A. Bittencourt

Material preparado com base nas aulas de Martin Stepp. Usa materiais de M. Ernst, S. Reges, D. Notkin, R. Mercer, Wikipedia

(2)

Bugs e Testes

• Bugs são inevitáveis em qualquer software complexo.

– Estimativas da indústria: 10-50 bugs por 1000 linhas de

código.

– Um bug pode ser visível ou pode se esconder em seu código

até bem mais tarde.

• Testes: Tentativa sistemática de revelar erros.

– Teste falhou: um erro foi demonstrado.

– Teste passou: erros não foram encontrados (nesta situação

particular).

(3)

Testes de Unidade

• Teste de unidade: Procura erros em um subsistema isolado.

– Geralmente, um “subsistema" significa um arquivo, uma classe ou

objeto em particular.

– A biblioteca Java JUnit ajuda a realizar testes de unidade

facilmente.

• Ideia básica:

– Para uma dada classe Foo, crie outra classe FooTest para

testá-la, contendo vários métodos que são “casos de teste”.

– Cada método procura resultados específicos e passa (ou falha).

• JUnit provê comandos "assert" para ajudar a escrever testes.

– A ideia: Coloque chamadas de asserções em seus métodos de

teste para checar coisas que você espera serem verdadeiras. Se

não forem, o teste vai falhar.

(4)

JUnit e Eclipse

• Para adicionar JUnit a um projeto Eclipse, clique:

– Project  Properties  Build Path  Libraries 

Add Library...  JUnit  JUnit 4  Finish

• Para criar um caso

de teste:

– Botão direito num arquivo

e escolha New  Test Case

– Ou clique File  New 

JUnit Test Case

– Eclipse pode criar stubs

(5)

Uma classe de teste JUnit

import org.junit.*;

import static org.junit.Assert.*;

public class Name {

...

@Test

public void name() {

// um método caso de teste

...

}

}

– Um método com @Test é marcado como um caso de teste JUnit.

• Todos os métodos @Test rodam quando JUnit roda a sua classe de

teste.

(6)

Métodos de asserção JUnit

• Cada método pode receber também uma string a ser

mostrada, caso ele falhe:

– e.g. assertEquals("message", expected, actual)

– Por que não há método pass?

assertTrue(test) Falha se o teste booleano for false assertFalse(test) Falha se o teste booleano for true assertEquals(expected, actual) Falha se os valores não forem iguais

assertSame(expected, actual) Falha se os valores não forem os mesmos

(por ==)

assertNotSame(expected, actual) Falha se os valores forem os mesmos

(por ==)

assertNull(value) falha se o valor dado for não null

assertNotNull(value) Falha se o valor for null

(7)

Teste JUnit de uma ArrayIntList

import org.junit.*;

import static org.junit.Assert.*;

public class TestArrayIntList {

@Test

public void testAddGet1() {

ArrayIntList list = new ArrayIntList(); list.add(42); list.add(-3); list.add(15); assertEquals(42, list.get(0)); assertEquals(-3, list.get(1)); assertEquals(15, list.get(2)); } @Test

public void testIsEmpty() {

ArrayIntList list = new ArrayIntList(); assertTrue(list.isEmpty()); list.add(123); assertFalse(list.isEmpty()); list.remove(0); assertTrue(list.isEmpty()); } ...

(8)

Rodando um teste

• Botão direito nele no Package Explorer do Eclipse à

esquerda; e então escolha:

Run As  JUnit Test

• A barra do JUnit vai mostrar

verde se todos os testes passarem,

vermelho

se algum teste falhar.

• O Failure Trace mostra que testes

falharam, se algum falhou,

(9)

Exercício com JUnit

Dada uma classe

Date com os seguintes métodos:

– public Date(int year, int month, int day) – public Date() // hoje

– public int getDay(), getMonth(), getYear()

– public void addDays(int days) // avance por days

– public int daysInMonth()

– public String dayOfWeek() // e.g. “Sunday"

– public boolean equals(Object o)

– public boolean isLeapYear() // é ano bissexto

– public void nextDay() // avance um dia

– public String toString()

• Escreva testes de unidade para checar o seguinte:

– Que nenhum objeto Date alcance um estado inválido.

– Que o método addDays funcione apropriadamente.

• Ele deve ser eficiente o bastante para adicionar 1.000.000 de dias em

apenas uma chamada.

(10)

O que há de errado aqui?

public class DateTest { @Test

public void test1() {

Date d = new Date(2050, 2, 15); d.addDays(4); assertEquals(d.getYear(), 2050); assertEquals(d.getMonth(), 2); assertEquals(d.getDay(), 19); } @Test

public void test2() {

Date d = new Date(2050, 2, 15); d.addDays(14); assertEquals(d.getYear(), 2050); assertEquals(d.getMonth(), 3); assertEquals(d.getDay(), 1); } }

(11)

Asserções bem estruturadas

public class DateTest { @Test

public void test1() {

Date d = new Date(2050, 2, 15); d.addDays(4);

assertEquals(2050, d.getYear()); // valor esperado

assertEquals(2, d.getMonth()); // deve estar

assertEquals(19, d.getDay()); // à ESQUERDA

}

@Test

public void test2() {

Date d = new Date(2050, 2, 15); d.addDays(14);

assertEquals(“ano após +14 dias", 2050, d.getYear()); assertEquals(“mês após +14 dias", 3, d.getMonth()); assertEquals(“dia após +14 dias", 1, d.getDay()); } // casos de teste normalmente devem ter mensagens

} // explicando o que está sendo checado, para // melhor compreensão da falha

(12)

Objetos de resposta esperada

public class DateTest { @Test

public void test1() {

Date d = new Date(2050, 2, 15); d.addDays(4);

Date expected = new Date(2050, 2, 19);

assertEquals(expected, d); // use um objeto de resposta

} // esperada para minimizar

// testes

// (Date deve ter os métodos

@Test // toString e equals)

public void test2() {

Date d = new Date(2050, 2, 15); d.addDays(14);

Date expected = new Date(2050, 3, 1);

assertEquals(“data após +14 dias", expected, d); }

(13)

Nomeando casos de teste

public class DateTest { @Test

public void test_addDays_withinSameMonth_1() { Date actual = new Date(2050, 2, 15);

actual.addDays(4);

Date expected = new Date(2050, 2, 19);

assertEquals("date after +4 days", expected, actual); }

// dê aos métodos de casos de tese nomes descritivos // realmente longos

@Test

public void test_addDays_wrapToNextMonth_2() { Date actual = new Date(2050, 2, 15);

actual.addDays(14);

Date expected = new Date(2050, 3, 1);

assertEquals("date after +14 days", expected, actual); }

// dê nomes descritivos aos valores esperados/reais

(14)

O que há de errado aqui?

public class DateTest { @Test

public void test_addDays_addJustOneDay_1() { Date actual = new Date(2050, 2, 15);

actual.addDays(1);

Date expected = new Date(2050, 2, 16); assertEquals(

“deveria ser " + expected + "\n" +

" mas em vez disso foi " + actual\n", expected, actual);

} ... }

(15)

Boas mensagens de asserção

public class DateTest { @Test

public void test_addDays_addJustOneDay_1() { Date actual = new Date(2050, 2, 15);

actual.addDays(1);

Date expected = new Date(2050, 2, 16);

assertEquals(“adicionando um dia a 2050/2/15", expected, actual);

} ... }

// JUnit já irá mostrar os // valores esperados e reais // em sua saída;

//

// não precisa repeti-los // na mensagem de asserção

(16)

setUp e tearDown

@Before

public void name() { ... }

@After

public void name() { ... }

– Métodos que rodam antes/depois de cada caso de teste

ser chamado

@BeforeClass

public

static

void name() { ... }

@AfterClass

public

static

void name() { ... }

– Métodos que rodam apenas uma vez antes/depois da

classe de teste inteira rodar

(17)

Dicas para testes

• Você não pode testar toda entrada possível, valor de

parâmetro, etc.

– Portanto, você deve pensar num conjunto limitado de testes para

expor prováveis bugs.

• Pense em casos-limite

– Números positivos; zero; negativos

– Exatamente no limite do tamanho de uma array ou coleção

• Pense em casos vazios e casos de erro

– 0, -1, null; uma lista ou array vazia

• Teste comportamento combinado

– Talvez add funcione normalmente , mas falhe depois de você

chamar

remove

– Faça múltiplas chamadas; talvez size falhe apenas na segunda

vez

(18)

O que há de errado aqui?

public class DateTest {

// teste todos os dias do ano

@Test(timeout = 10000)

public void tortureTest() {

Date date = new Date(2050, 1, 1); int month = 1;

int day = 1;

for (int i = 1; i < 365; i++) { date.addDays(1);

if (day < DAYS_PER_MONTH[month]) {day++;}

else {month++; day=1;} assertEquals(new Date(2050, month, day), date); }

}

private static final int[] DAYS_PER_MONTH = {

0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec

(19)

Testes fidedignos

• Teste uma coisa por vez para cada método de teste.

– 10 testes pequenos são muito melhores que um teste 10x maior.

• Cada método de teste devia ter poucas (talvez uma)

instruções de asserção.

– Se você fizer asserções demais, a primeira que falhar, pára o teste.

– Você não vai saber se uma asserção posterior teria falhado.

• Testes devem evitar muita lógica.

– Minimize if/else, loops, switch, etc.

• Testes tortura são ok, mas somente em adição a testes

simples.

(20)

Desenvolvimento dirigido por testes

• Testes de unidade podem ser escritos depois, durante ou

mesmo antes de codificar.

– test-driven development (TDD): escreva os testes, só depois

escreva o código para passar nos testes.

• Imagine que nós gostaríamos de adicionar um método

subtractWeeks a nossa classe Date, que desloca

esta

Date para trás no tempo por um dado número de

semanas.

• Escreva o código para testar este método antes que ele

tenha sido escrito.

– Então, assim que implementarmos o método, saberemos se

ele funciona.

(21)

Suítes de teste

• Suíte de teste: Uma classe que roda vários testes

JUnit.

– Um modo fácil de rodar todos os testes de sua aplicação

de uma só vez.

import org.junit.runner.*;

import org.junit.runners.*;

@RunWith(Suite.class)

@Suite.SuiteClasses({

TestCaseName1.class,

TestCaseName2.class,

...

TestCaseNameN.class,

})

(22)

Exemplo de suíte de testes

import org.junit.runner.*;

import org.junit.runners.*;

@RunWith(Suite.class)

@Suite.SuiteClasses({

WeekdayTest.class,

TimeTest.class,

CourseTest.class,

ScheduleTest.class,

CourseComparatorsTest.class

})

(23)

Sumário - JUnit

• Testes necessitam de atomicidade de falha (habilidade de saber

exatamente o que falhou).

– Cada teste deve ter um nome claro, longo e descritivo.

– Asserções devem ter sempre mensagens claras para saber o que falhou.

– Escreva muitos testes pequenos, e não um grande teste.

• Cada teste devia ter , grosso modo, apenas uma asserção em seu final.

• Sempre use um parâmetro de timeout para todos os testes.

• Teste por erros esperados / exceções.

• Escolha um método de asserção descritivo, e não sempre o

assertTrue.

• Escolha casos de teste representativos de classes de entrada

equivalentes.

• Evite lógica complexa em métodos de teste, se possível.

Referências

Documentos relacionados

The Reflective Practitioner: How Professionals Think in Action... Metodologia da

MARIA DAS GRACAS SILVA NASCIMENTO SILVA Fem MARIA DAS GRACAS SOARES Fem MARIA DAS GRACAS VIANA DE SOUSA DIOGO Fem MARIA DE FATIMA SILVA LIMA Fem MARIA DO CARMO DOS SANTOS Fem MARIA

Esta característica típica de todos os primeiros estágios MARES é fundamental para obter uma ótima afinação do 2° estágio capaz de garantir o melhor rendimento dura n t e todo

(2004) que buscou verificar estatisticamente a existência de diferenças da produtividade da População Economicamente Ativa – PEA por gênero no estado do Rio Grande do

Assim, entre 1962 e 1979, foram conturbadas as relações turco-americanas, mesmo que esses desvios não tenham reorientado a política externa turca como um tudo,

Di fatto, celebrare l’Avvento è accogliere i segni della venuta del Regno Divino nella nostra vita, come un’apertura alla Novità che trasforma la realtà del mondo e del

Foi visto, então, que, nos tempos e espaços de atuação dos jovens, organizados em torno de um princípio inclusivo de interação simbólica entre códigos e valores tradicionais de

A análise dos dados meteorológicos foi dividida em três etapas a partir de um esquema de decomposição temporal-cronológica, iniciando pela série de dados de longo