sexta-feira, 27 de fevereiro de 2009

Funcionamento dos frameworks xUnit - Parte 2/2

Para complementar o descrito na Parte 1, vamos ver o uso de test fixtures e dos métodos setUp e tearDown.

Em muitos casos quando estamos construindo uma classe de testes para verificar determinada funcionalidade, diversos métodos de teste irão operar sobre um mesmo objeto ou conjunto de objetos. Ao escrevermos código para configurar o estado destes objetos repetidamente, em cada método de teste, estaremos duplicando código desnecessariamente.

Ao invés disto, podemos utilizar um test fixture, isto é,  um conjunto de dados de teste que será compartilhado por diversos testes. Geralmente este conjunto de dados serão objetos que alocaremos para serem verificados nos testes.

Para fazer isto numa xUnit, geralmente existem os métodos setUp e tearDown. No primeiro alocamos e configuramos os objetos que serão usados nos diversos métodos de teste. No segundo, destruímos estes objetos.

Como você já deve ter imaginado, estes objetos serão atributos da classe de testes, para que possam ser alocados por setUp e desalocados por tearDown.

A sua classe de teste, filha de TestCase, executa cada um dos métodos de teste que você criou da seguinte forma:

  • chama setUp
  • chama seu método de teste
  • chama tearDown

Ou seja, cada método de teste é sempre executado depois de setUp e antes de tearDown, o que permite que os objetos configurados (fixtures) sejam usados em seu teste e logo após descartados.

Esse comportamento faz com que cada método de teste possa ser executado sempre da forma, como se os objetos sob os quais ele opera estivessem “recém configurados”. O método tearDown garante que o dado configurado para o teste seja “resetado” para o próximo teste, fazendo com que os dados de um teste não interfiram no comportamento de outro.

Exemplo (CppUnit):

class TesteContaBancaria : public TestCase
{
public:
...
void setUp();
void tearDown();

private:

void FicaNegativaAoSacarValorMaiorQueSaldo();
void FicaNegativaAoTransferirValorMaiorQueSaldo();

ContaBancaria *_conta; // fixture
};

...

void TesteContaBancaria::setUp()
{
// configura a conta para ser usada nos testes
_conta = new ContaBancaria();
_conta->DefinirSaldo( 1000.00 );
}

void TesteContaBancaria::tearDown()
{
delete _conta;
}

void TesteContaBancaria::FicaNegativaAoSacarValorMaiorQueSaldo()
{
_conta->Sacar( 1000.01 );

assert( _conta->EstaComSaldoNegativo() );
}

void TesteContaBancaria::FicaNegativaAoTransferirValorMaiorQueSaldo()
{
ContaBancaria outraConta;

_conta->Transferir( 1000.01, outraConta );

assert( _conta->EstaComSaldoNegativo() );
}