DICAS

Visite a biblioteca de dicas da comunidade.

Saiba mais

ARTIGOS

Abordagens detalhadas sobre assuntos diversos.

Saiba mais

INICIANTES

Aprenda a programar de um modo simples e fácil.

Saiba mais

DOWNLOADS

Acesse os materiais exclusivos aos membros.

Saiba mais
voltar

PARA QUEM GOSTA DE DELPHI

Refatorando padrões. Um exemplo de TDD codificado em Delphi. Artigo 01, o básico.

Artigo originalmente escrito por Yanniel em inglês, veja a referencia ao final da página.

O objetivo deste artigo não é discutir os prós e contras de TDD, teste unitário ou qualquer. O objetivo é apenas dar alguns exemplos.

Se necessário, para uma rápida compreensão do que é TDD ou Teste de Unidade , consulte os seguintes links.

Veja mais sobre TDD
Veja mais sobre DUnit

No TDD você não escreve o código da aplicação primeiro, em vez disso você deve começar escrevendo os casos de teste.
O ciclo TDD é o seguinte:
No começo, você apenas escreve um teste e, mais tarde, mais testes podem ser adicionados.

Certifique-se de que o teste inicial falhe; isso validará o chicote de teste.

Escreva algum código para passar no teste.
Importante: não exagere no código.

Adicione apenas o código necessário para passar no teste. O código não precisa ser elegante neste momento.

Execute o teste: se falhar, você terá que voltar para a etapa 3 e corrigir seu código para passar no teste.
Quando você tiver sucesso, passe para a etapa 5.

Melhore e otimize seu código: torne-o elegante, mais eficiente,
evite duplicações, etc, etc. Isso é chamado de refatoração de código.

Ao refatorar seu código, talvez, por acidente, você pode quebrar a funcionalidade (parar de funcionar).

Como você pode ter certeza de que tudo está funcionando como deveria?

Apenas execute novamente o teste e ele informará se a refatoração anterior apresentou uma falha ou não.

Vá para a etapa 1 e adicione um novo teste, se necessário.

O exemplo: vamos considerar o jogo de xadrez.
O objetivo será implementar o código para verificar se uma peça é colocada em uma
posição válida dentro da placa.

Nós só vamos implementar um teste: “SetPositionTest” .

Vou numerar as colunas (coordenada X) de 1 a 8 começando no canto inferior esquerdo.
Do mesmo modo, numerarei as linhas (coordenada Y) de 1 a 8, iniciando no canto inferior esquerdo.

8
7
6
5
4
3
2
1 2 3 4 5 6 7 8

Para um tutorial passo a passo de como usar, configurar e configurar o DUnit, você pode ler as versões em inglês ou chinês do tutorial.

Inicialmente, o código de teste deve ficar assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
unit ChessPiecesTests;
 
interface
 
uses
   TestFrameWork;
 
type
  TPieceTest = class(TTestCase)
  published
    procedure SetPositionTest;
  end;
 
implementation
 
uses
  ChessPieces;
 
{ TPieceTest }
 
procedure TPieceTest.SetPositionTest;
begin
end;
 
initialization
  TestFramework.RegisterTest(TPieceTest.Suite);
end.

Se você executar esse teste, ele será bem-sucedido porque nenhuma verificação está sendo executada dentro do procedimento SetPositionTest .

Cada teste é composto por uma ou mais verificações. Sugiro adicionar os controles aos poucos. Toda vez que você adiciona um cheque, você deve adicionar código da aplicação real para passar no teste correspondente.

Agora, vamos fazer o teste falhar de propósito. Para isso, vamos adicionar uma verificação ao procedimento SetPositionTest.

1
2
3
4
procedure TPieceTest.SetPositionTest;
begin
  Check(True = False, '');
end;

Obviamente, verdadeiro nunca é falso. Então, esse teste irá falhar. Se não falhar, então algo está errado com a sua IDE!

Agora, vamos adicionar um cheque(colocar o rei inimigo em perigo) ao nosso teste.
Veja o exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
procedure TPieceTest.SetPositionTest;
var
  Piece: TPiece;
begin
  Piece:= TPiece.Create;
  try
    //Test trivial (normal) workflow
    Check(Piece.SetPosition(4, 4) = True, '');
  finally
    Piece.Free;
  end;
end;

Se você executar este teste, você receberá um erro de compilação! Sim está certo.
Você ainda não tem código comercial. Você acabou de fazer o teste.
É disso que se trata o TDD: teste primeiro, código de negócios mais tarde. Entenda a ideia?

Para evitar o erro de compilação, vamos codificar uma unidade separada ( chesspieces ) e
vamos adicioná-la à usos cláusula do nosso ChessPiecesTests unidade.

Esta unidade será utilizada como apoio nos testes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
unit ChessPieces;
 
interface
 
type
  TPiece = class
  private
  public
    function SetPosition(aX, aY: Integer): Boolean;
  end;
 
implementation
 
{ TPiece }
 
function TPiece.SetPosition(aX, aY: Integer): Boolean;
begin
end;
 
end.

Execute o teste novamente e agora o erro de compilação desapareceu. No entanto, o teste falha porque o Piece.SetPosition (4, 4) é avaliado como Falso .

Vamos adicionar o código comercial mínimo possível para passar este teste:

1
2
3
4
function TPiece.SetPosition(aX, aY: Integer): Boolean;
begin
  Result:= True;
end;

Reforçando que aqui o objetivo é passar como verdadeiro no teste com o mínimo possível de código.

OK, e agora? Bem, continuamos adicionando novas verificações ao teste e, sempre que isso acontece,
precisamos adicionar um novo código de negócios para poder transmiti-lo. É muito importante adicionar
verificações para testar os limites do que estamos tentando codificar.

No exemplo abaixo haverá varias validações:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
procedure TPieceTest.SetPositionTest;
var
  Piece: TPiece;
begin
  Piece:= TPiece.Create;
  try
    //Test trivial (normal) workflow
    Check(Piece.SetPosition(4, 4) = True, '');
 
    //Tests boundaries
    Check(Piece.SetPosition(1, 1) = True, '');
    Check(Piece.SetPosition(1, 8) = True, '');
    Check(Piece.SetPosition(8, 1) = True, '');
    Check(Piece.SetPosition(8, 8) = True, '');
 
    //Test beyond the boundaries
    Check(Piece.SetPosition(3, 15) = False, '');
    Check(Piece.SetPosition(3, -15) = False, '');
    Check(Piece.SetPosition(15, 3) = False, '');
    Check(Piece.SetPosition(15, 15) = False, '');
    Check(Piece.SetPosition(15, -15) = False, '');
    Check(Piece.SetPosition(-15, 3) = False, '');
    Check(Piece.SetPosition(-15, 15) = False, '');
    Check(Piece.SetPosition(-15, -15) = False, '');
  finally
    Piece.Free;
end;

O teste acima está até mesmo verificando as tentativas de posicionar uma peça fora do tabuleiro de xadrez.

Para passar esse teste, vamos escrever algum código de negócio:

1
2
3
4
5
6
function TPiece.SetPosition(aX, aY: Integer): Boolean;
begin
  Result:= True;
  if (aY < 1) or (aY > 8) then Result:= False
  else if (aX < 1) or (aX > 8) then Result:= False;
end;

Execute o teste e veja como ele passa.

Certo, agora vamos analisar. O código acima poderia ser refatorado ou mesmo reescrito.
Os testes permanecerão os mesmos, permitindo-nos capturar quaisquer erros introduzidos com a alteração do código.

Uma nova forma de escrever o procedimento acima pode ser esta:

1
2
3
4
5
6
7
function TPiece.SetPosition(aX, aY: Integer): Boolean;
begin
  Result:= (aX > 0) and
           (aX < 9) and 
           (aY > 0) and
           (aY < 9);
end;

Execute o teste e ele informará se essa refatoração (ou reimplementação) funciona corretamente.

É importante observar que um bom teste deve abranger todos os cenários e fluxos de trabalho possíveis.
Preste atenção especial aos limites. Neste ponto, uma boa compreensão dos requisitos é indispensável.

Finalmente, mais e mais testes serão necessários em uma aplicação no mundo real.
Cada teste terá suas próprias verificações.

Cada teste irá cobrir uma parte da funcionalidade, observe, é para isso que o teste unitário é destinado.

Traduzido e adaptado de http://www.yanniel.info/2012/03/tdd-in-delphi-dunit-framework.html

Dúvidas ou sugestões? Deixe o seu comentário!

Facebook Comments Box
  • Giovani Da Cruz
  • 1.961 views
  • 0 comentários
  • 21 de março de 2019

Está gostando do conteúdo? Considere pagar um cafezinho para nossa equipe!

Deixe um comentário

Ir ao topo

© 2024 Infus Soluções em Tecnologia - Todos os Direitos Reservados