• Nenhum resultado encontrado

Objetos Dublês (Test Doubles)

No documento Padrões de testes automatizados (páginas 88-92)

Algumas vezes é difícil testar um sistema porque ele pode depender de componentes que são difíceis de serem utilizados em um ambiente de teste [93, 138]. Tais componentes podem ser bancos de dados, sistemas de arquivos, redes, serviços Web, bibliotecas e até mesmo do relógio do computador, no caso de funcionalidades que envolvem datas e instantes.

1 // Referências do TestNG

2 import org.testng.annotations.*;

3

4 // Após a execução desta classe de teste, será impresso no console: 5 // @BeforeSuite => @BeforeTest => @BeforeClass

6 // @BeforeMethod => @Test: teste 1 => @AfterMethod 7 // @BeforeMethod => @Test: teste 2 => @AfterMethod 8 // @AfterClass => @AfterTest => @AfterSuite

9 public class TestNGExemplo {

10 /* Métodos de set up */

11 @BeforeSuite public void antesDeTodasAsClassesDeTestes() {

12 System.out.print("@BeforeSuite => ");

13 } 14

15 // Ao contrário do BeforeClass, BeforeTest roda mesmo que não tenha teste

16 @BeforeTest public void antesDessaClasseDeTestes() {

17 System.out.print("@BeforeTest => ");

18 }

19

20 @BeforeClass public void antesDoPrimeiroMetodoDeTesteDessaClasse() {

21 System.out.println("@BeforeClass");

22 } 23

24 @BeforeMethod public void antesDeCadaMetodoDeTesteDessaClasse() {

25 System.out.print("@BeforeMethod => ");

26 } 27

28 /* Métodos de tear down */

29 @AfterMethod public void depoisDeCadaMetodoDeTesteDessaClasse() {

30 System.out.println("@AfterMethod");

31 } 32

33 @AfterClass public void depoisDoPrimeiroMetodoDeTesteDessaClasse() {

34 System.out.print("@AfterClass => ");

35 } 36

37 @AfterTest public void depoisDessaClasseDeTestes() {

38 System.out.print("@AfterTest => ");

39 }

40

41 @AfterSuite public void depoisDeTodasAsClassesDeTestes() {

42 System.out.print("@AfterSuite");

43 }

44

45 /* Métodos de teste */

46 @Test public void metodoDeTeste1() {

47 System.out.print("@Test: teste 1 => ");

48 }

49

50 @Test public void metodoDeTeste2() {

51 System.out.print("@Test: teste 2 => ");

52 }

53 }

1 // Referências do TestNG

2 import org.testng.annotations.*;

3 // Referências do sistema em teste ocultas 4

5 public class PilhaComTamanhoLimitadoTests {

6 Pilha pilha; // variável utilizada em todos os testes

7

8 /* Set up */

9 @Before public void inicializaObjetos() {

10 pilha = new Pilha() ;

11 }

12

13 /* Tear down */

14 @After public void liberaMemoria() {

15 pilha.esvazia() ;

16 pilha = null;

17 System.gc() ; // Agilizando a execução do Garbage Collector

18 } 19

20 // Teste que consome bastante memória

21 @Test public void pilhaNaoAceitaMaisElementosDoQueLimiteEstipulado() {

22 pilha.setAlturaMaxima(1000) ;

23 for(int i = 0; i < 1000; i++)

24 pilha.coloca(i);

25 assertEquals(1000 , pilha.altura() );

26 pilha.coloca(i);

27 assertEquals(1000 , pilha.altura() );

28 } 29 }

em vez de testes de integração. Primeiramente, os testes de unidade solucionam os problemas de baixa testabilidade do sistema em teste. Além disso, todas as outras características de qualidade, descritas na Seção 5.1, são mais facilmente asseguradas quando um cenário de teste é isolado, ou seja, ele tende a ficar mais rápido, independente e repetitível.

O que caracteriza um teste de unidade é justamente o isolamento de um trecho de código do resto do sistema e do ambiente. Isolar um trecho de código significa substituir todas as suas dependências, que podem ter implementações lentas, incompletas ou que prejudicam a testabilidade, por dependências controladas. Dessa maneira, o trecho de código em teste trabalha sob situações ideais, supondo que todas suas dependências estão corretas. Inclusive, essa característica ajuda a dispensar a prática de depuração, pois, se algum teste falhar, fica explícito o trecho de código que está o problema.

No entanto, isolar um trecho de código pode ser uma tarefa complicada. A dificuldade deve-se principalmente à testabilidade do sistema (Seção 10.3). Quanto mais entrelaçado estiverem os módulos em teste, mais difícil será para substituir as dependências por objetos controlados [113].

Dado que um módulo é suficientemente coeso para isolar seu comportamento, é possível que isso seja feito comumente de duas maneiras: a primeira é inserir, errôneamente, lógica de teste no código de produção, que é um indício de problema (Seção 5.2); a segunda, mais elegante, é fazer com que os testes substituam, apenas dentro do seu contexto e durante sua execução, as dependências da funcionalidade em teste por módulos e objetos que apenas respondam o que o cenário de teste espera para poder fazer suas verificações.

No caso de linguagens orientada a objetos, os testes podem substituir os objetos dependentes por objetos equivalentes, mas que possuem o comportamento mínimo desejado para realização do teste. Por exemplo, através de herança, pode-se criar subclasses que sobrescrevem a implementação original por uma simplificada. Nas linguagens em que até os métodos são objetos, é possível, simplesmente, substituí-los por implementações temporárias durante a execução do cenário de teste. Ainda, existem bibliotecas, tais como Mockito, EasyMock e JMock para Java, que criam objetos que seguem o compor- tamento desejado, sem a necessidade de implementá-los.

Esses objetos que são criados no escopo dos testes para substituir dependências são chamados gener- icamente de Objetos Dublês, em analogia aos dublês de cinema [99]. Contudo, há diversos tipos de Objetos Dublês (Figura 6.7), que são apropriados para situações específicas. Nas seções 6.4.3 até 6.4.7 há a descrição detalhada dos cinco tipos de Objetos Dublês já descritos por Meszaros: Objeto Tolo, Stub, Falsificado, Emulado e Espião, respectivamente. Na Seção 6.4.8, é descrito um novo tipo que foi identificado pelo autor, o Objeto Protótipo.

A escolha do tipo de Objeto Dublê a ser utilizado depende prioritariamente do que se está querendo verificar, pois nem todos eles podem ser utilizados dentro de um contexto. Por exemplo, somente os Ob- jetos Falsificados e os Espiões são capazes de imitar um algoritmo, ou seja, de fornecer dados dinâmicos para a funcionalidade em teste.

A Tabela 6.1 faz uma comparação dos objetos dublês de acordo com quatro características impor- tantes: (1) se o dublê é exercitado pelo teste, ou seja, se ele influencia diretamente no resultado do teste; (2) se o dublê fornece informações enganosas que influenciam no resultado gerado pela funcionalidade em teste, sejam elas dados estáticos ou gerados dinamicamente por algoritmos simplificados; (3) a ca- pacidade do dublê de armazenar informações sobre o que foi executado, o que permite fazer verificaçoes na forma que um algoritmo é executado e (4) caso o objeto dublê precise ou não seguir uma interface definida, o que pode ser importante para realizar testes de algoritmos reflexivos ou com programação a aspectos.

Depois que se sabe quais padrões são viáveis de serem utilizados, a escolha deve-se basear na sim- plicidade, ou seja, qual deles torna a implementação do teste mais enxuta e legível. Por exemplo, Se o objeto servirá apenas para evitar erros de compilação ou erros indiretos de execução, ou seja, ele não será exercitado diretamente pelo teste, então Objeto Tolo é o que deve ser escolhido porque é o mais fácil de implementar. No entanto, não existe uma regra para isso, pois varia de acordo com as particularidades

de cada contexto e das ferramentas disponíveis de objetos dublês. Mais detalhes e exemplos são podem ser encontrados na Seção 6.4.

Figura 6.7: Tipos de Objetos Dublês.

❤❤ ❤❤ ❤❤ ❤❤ ❤❤ Objeto Dublê Características

Exercitado pelo Teste Fornecimento de Dados para o SUT Armazena Informações da Execução Interface Predefinida Objeto Tolo (Dummy Object) Não Não Fornece Não Sim

Objeto Stub (Test Stub) Sim Estático ou Dinâmico Não Sim Objeto Falsificado (Fake Object) Sim Estático ou Dinâmico Não Sim Objeto Emulado (Mock Object) Sim Estático Sim Sim Objeto Espião (Spy Object) Sim Estático ou Dinâmico Sim Sim Objeto Protótipo Sim Estático Não Não

Tabela 6.1: Comparação de algumas características dos Objetos Dublês.

No documento Padrões de testes automatizados (páginas 88-92)