Mostrando postagens com marcador Frameworks. Mostrar todas as postagens
Mostrando postagens com marcador Frameworks. Mostrar todas as postagens

quinta-feira, 17 de janeiro de 2013

FirefoxOS

Esse eu não adicionei na minha lista de Coisas que devem bombar em 2013, mas acho que futuramente ele poderá estar em muitos celulares e tablets que vemos por aí, concorrendo com o Android. Difícil acontecer? Também acho, olhando o cenário atual, mas há alguns bons motivos pra que isso aconteça.

Em 2011, o diretor de pesquisas da Mozilla Corporation, Andreas Gal, anunciou o projeto Boot to Gecko (pra quem não conhece, o Gecko é o renderizador de páginas usado pelo  navegador Firefox). A ideia básica do projeto é a de construir um sistema operacional realmente livre, baseado em padrões abertos da web, como o HTML5 e o JavaScript. O projeto foi rebatizado em 2012 como FirefoxOS.

firefox_os_screenshots

Tá, mas o Android não é opensource? Sim e não. Você pode baixar o código, compilá-lo em sua máquina, mas não pode gerar novas versões “oficiais” sem a liberação de sua mantenedora, a Google. Isso é bom por um lado, pois impede a explosão de versões, como acontece no Linux, e dá mais segurança aos fabricantes de celulares para construir hardwares compatíveis, mas é ruim por outro, pois o controle do sistema operacional não é da comunidade, o que prende o produto às políticas e estratégias da empresa, que não são necessariamente a dos desenvolvedores. Você pode ler mais sobre essa discussão aqui, aqui e aqui.

Os outros players do mercado são o iOS (Apple), o Windows Phone (Microsoft) e (ainda) o Blackberry, e, como você sabe, eles são totalmente fechados. Mas não é a questão “ser aberto” ou “ser fechado” que realmente importa. O problema maior talvez seja que os desenvolvedores de aplicativos para dispositivos móveis tenham que criar versões diferentes para cada sistema operacional com que queiram trabalhar, porque suas APIs são bem diferentes.

Talvez o mais importante do FirefoxOS é o uso de uma WebAPI, em que a comunicação entre o SO e a aplicação é realizada através de HTTP, deixando a aplicação desacoplada dos detalhes do SO. Você envia a requisição via GET ou POST e recebe a resposta como XML ou JSON, o que é extremamente comum hoje para quem desenvolve aplicações web. Além de ser natural para muitos desenvolvedores, diminuindo a curva de aprendizado em comparação à outras APIs, reduz o custo de investimento da empresa, tanto na contratação de funcionários fortemente especializados, como em treinamento, uma vez que esses padrões abertos (HTML, CSS, JavaScript, JSON, XML, etc.) já estão bem difundidos.

Será bastante difícil que o FirefoxOS cresça tão rápido como foi com o Android e, ainda assim, ameace sua hegemonia atual. Muita gente já investiu nessa plataforma e não quer jogar fora o que gastou. Mas pode ser que comecem a considerar o FirefoxOS como uma opção interessante, de baixo investimento e possível bom retorno. Para isso, é preciso o apoio – e investimento – dos fabricantes (como já fez a Qualcomm e a Deutsche Telekom e está fazendo a Telefónica), ganhar visibilidade (o que está acontecendo, em vista de sua participação nas grandes eventos da área, como a Mobile World Congress) e mostrar seus benefícios frente aos concorrentes. Nesse último item, entra a web como plataforma.

The web is the plataform

A ideia de “web como plataforma” pode consagrar frameworks como o PhoneGap para a construção de aplicações que rodem nos diversos SOs e pode acabar com os problemas de criar aplicações diferentes para cada sistema operacional.

Se a web se tornar o padrão para dispositivos móveis, criar aplicações usando o Android SDK, o Windows Phone SDK, o iOS SDK, ou qualquer outro, será coisa do passado.

E com todos os recursos do HTML5, CSS3 e do JavaScript (ECMA Script 5, vindo a versão 6 por aí…), é possível que isso acabe acontecendo.

Enfim, mesmo que o FirefoxOS não emplaque, a ideia de ter a web como o padrão para construção de aplicações faz cada vez mais sentido.

quarta-feira, 25 de maio de 2011

Dojo I

No penúltimo sábado (14/05/2011) conduzi o I CEFET/NF Coding Dojo, o primeiro Dojo de codificação do CEFET Nova Friburgo/RJ. O evento teve a seguinte configuração:

O evento, apesar de pequeno, foi bastante divertido. A maioria não conhecia TDD e ficou intrigada com a maneira de pensar e construir software dessa forma. Essa quebra de paradigma foi percebida de maneira bastante positiva. Todos se sentiram desafiados e tentados a pensar diferente, resolvendo o problema de um ponto de vista, até então, inusitado.

O desafio foi bem simples, até porque o objetivo era usar o desafio como pretexto para o aprendizado de TDD, como é praxe dos dojos. Foi usado o velho e bom Jokenpo (ou “Pedra, Papel e Tesoura”, como muitos conhecem).

codeblocks1

Foi usado C++ (que é presente na grade do curso técnico de Informática do CEFET) e a biblioteca Yaffut, que é simples, compacta e portátil, facilitando seu aprendizado e uso em diferentes ferramentas.

codeblocks2

Não tenho a intensão de publicar todos os slides que usei nesse Dojo aqui, mas deixarei o de TDD com C++. Como esse Dojo era mais “light”, só passei a Parte 1, que compreende o uso do Yaffut. Fica aí o conteúdo pra quem pretender experimentar… ;)

quarta-feira, 17 de novembro de 2010

Bons frameworks C++ para criação automática de mocks

Frameworks para criação automática de objetos substitutos (“mocks”) em C++ foram evoluindo num passo muito mais lento que os para Java, C# ou mesmo Ruby. A dificuldade de criar uma boa arquitetura para simulação da criação automática sem perder a portatilidade entre compiladores e também a falta de desenvolvedores para melhorar os frameworks contribuiram para esse atraso.

Ainda há poucos frameworks altamente portáteis e, menos ainda, estáveis, mas alguns funcionam bem para a maioria dos casos. Há projetos bem estáveis e portáteis, como Google Mock ou MockPP, mas que não abrangem a criação automática de objetos substitutos. Neles, é preciso criar uma classe substituta (implementando a interface que se deseja simular) e usar macros para gerar os métodos.

Os frameworks de geração automática em C++ geralmente exploram o modelo de representação interna (layout ABI) de classes usado em um determinado compilador. Combinado ao uso de templates e algumas técnicas como Fast Delegates, é feito a geração do código na hora da declaração. Como o uso da representação interna varia de compilador para compilador (se bem que em muitos a representação é parecida), alguns projetos deixam de adicionar a compatibilidade com determinados compiladores - até pelo fato de faltar desenvolvedores interessados (ou habilitados) em fazer a adaptação.

Exemplo base

Para exemplificar o uso dos frameworks, tomarei por base o simples código abaixo:

class Piada
{
public:
Piada(const string &autor, const string &texto)
: _autor( autor ), _texto( texto )
{
}
// ... gets e sets
private:
// ... ctor, dtor, ops...
string _autor;
string _texto;
};


// Piada retirada de: http://confiar.atspace.com/curtas_boas.htm
const Piada PIADA_TOSCA( "Desconhecido",
"Você conhece a piada do fotógrafo ? Ainda não foi revelada." );


class RepositorioPiada
{
public:
virtual ~RepositorioPiada() {};
// ...
virtual bool Existe() const = 0;
virtual void Adicionar(const Piada &piada) = 0;
virtual void Alterar(const Piada &piada) = 0;
// ...
};

class ServicoPiada
{
public:
ServicoPiada(RepositorioPiada &repositorio)
: _repositorio( repositorio )
{
}
//...
void Salvar(const Piada &piada)
{
if ( _repositorio.existe( piada ) )
_repositorio.alterar( piada );
else
_repositorio.adicionar( piada );
}
private:
//...
RepositorioPiada _repositorio;
};


Na maioria dos exemplos será feito o uso do UnitTest++, com o qual todos são compatíveis.


Isolator ++


Começando por uma opção paga, lançada mês passado, o Isolator ++ possui uma característica extremamente rara em relação aos concorrentes: permite criar substitutos para classes concretas, métodos não virtuais e métodos estáticos. Além disso, funciona em conjunto como alguns frameworks de teste populares: Google Test, UnitTest++, Yaffut, CPPUnit e Boost::Test.


Porém, ele tem algumas limitações consideráveis, na versão avaliada durante esse post: só funciona com o Visual Studio (2008 e 2010) e métodos abstratos (ex: virtual void FazAlgo() = 0;) devem ser declarados com a macro PURE do Visual Studio (ex: virtual void FazAlgo() = PURE;), algo que eles pretendem resolver na próxima versão. Assim, o Isolator ++ tem grandes vantagens e desvantagens importantes que limitam sua abrangência. Por ser um produto novo e pago, deve evoluir rapidamente, o que torna seu futuro promissor.

TEST_F(TesteServicoPiada, DeveSalvarUmaPiadaNova)
{
RepositorioPiada *rp = FAKE<RepositorioPiada>();
WHEN_CALLED(rp->Existe( PIADA_TOSCA )).ReturnVal( false );

ServicoPiada servico( rp );
servico.Salvar( PIADA_TOSCA );

ASSERT_WAS_CALLED( rp->Adicionar( PIADA_TOSCA ) );
ISOLATOR_CLEANUP();
}

Acima um teste realizado com o Isolator ++. Repare o uso de FAKE para criação do objeto substituto, WHEN_CALLED para criação da expectativa, ASSERT_WAS_CALLED para verificar a chamada de um método e ISOLATOR_CLEANUP para a destruição dos objetos do Isolator ++.


AMOP


AMOP (Automatic Mock Object for C++) é um projeto de código aberto que conheci há uns dois anos (logo assim que surgiu) e teve poucas atualizações de lá pra cá, o que o fez permanecer com alguns bugs inconvenientes. Ele possui suporte ao Visual Studio, ao GCC e ao  C++ Builder 2009 – sendo o suporte a este último uma contribuição minha ao projeto – e funciona em conjunto com UnitTest++.

TEST_F(TesteServicoPiada, DeveSalvarUmaPiadaNova)
{
MockObject< RepositorioPiada > mock;

mock.call( &RepositorioPiada::Existe )
.expect( PIADA_TOSCA )
.returning( false );

mock.call( &RepositorioPiada::Adicionar )
.expect( PIADA_TOSCA );

ServicoPiada servico( mock );
servico.Salvar( PIADA_TOSCA );

mock.verify();
}

Acima um teste realizado com o AMOP. Repare uso de MockObject parametrizado para a criação do objeto substituto, do método call para criação da expectativa e do método verify para a verificação das expectativas criadas. O método verify não necessita ser chamado, pois é chamado automaticamente na destruição do objeto mock, que ocorre no fim do escopo do teste.


MockitoPP


O MockitoPP é a versão C++ do Mockito, projeto originalmente escrito em Java. De código aberto, é compatível com GCC e Visual Studio e pode ser usado com Google Test, o Hamcrest ou a Boost (regex). Venho usando exporadicamente há cerca de um ano e sinto que a versão atual apresenta poucos problemas (no GCC, era preciso colocar o operador < em algumas classes).

TEST(TesteServicoPiada, DeveSalvarUmaPiadaNova)
{
mock_object< RepositorioPiada > mock;

mock( &RepositorioPiada::Existe )
.when( PIADA_TOSCA )
.thenReturn( false );

mock( &RepositorioPiada::Adicionar )
.when( PIADA_TOSCA )
.thenReturn();

RepositorioPiada &rp = mock.getInstance();

ServicoPiada servico( mock );
servico.Salvar( PIADA_TOSCA );

ASSERT_TRUE( mock.verify( &RepositorioPiada::Existe ).exactly( 1 ) );
ASSERT_TRUE( mock.verify( &RepositorioPiada::Adicionar ).exactly( 1 ) );
}

Acima um teste realizado com MockitoPP. Repare o uso mock_object parametrizado para a criação do objeto substituto, do método when para criação da expectativa e do método verify para a verificação das expectativas criadas. Como pode ser visto, sua sintaxe é bem parecida com a AMOP, porém tendo mais opções de verifição de comportamento (veja a documentação no site).


HippoMocks


O HippoMocks é outro projeto de código aberto, compatível com GCC, Visual Studio e Comeau. O framework de testes usado pelo HippoMocks é o Yaffut, que reune as qualidades dos outros frameworks de teste (veja os detalhes na página do Yaffut). No que visto há cerca de um ano, tem boa estabilidade, sendo ligeiramente melhor que a do MockitoPP.

FUNC( DeveSalvarUmaPiadaNova )
{
MockRepository mocks;
RepositorioPiada *mock = mocks.InterfaceMock< RepositorioPiada >();

mocks.ExpectCall( mock, RepositorioPiada::Existe )
.With( PIADA_TOSCA )
.Return( false );

mocks.ExpectCall( mock, RepositorioPiada::Adicionar )
.With( PIADA_TOSCA );

ServicoPiada servico( mock );
servico.Salvar( PIADA_TOSCA );
}

Acima um teste realizado com HippoMocks. Repare que o objeto substituto é criado através do método InterfaceMock, da classe MockRepository. As espectativas são criadas usando ExpectCall e, ao final, elas são verificadas automaticamente.


Comparativo


O comparativo a seguir é subjetivo, mas mostra uma percepção prática dos frameworks em relação aos critérios julgados relevantes na escolha. A nota varia entre 1 e 4, sendo 1=Ruim, 2=Razoável, 3=Bom e 4=Ótimo.


comparacao


Pelo fato da estabilidade, pessoalmente, dou preferência ao uso de HippoMocks. Apesar disto, gosto de poder usar os matchers do Hamcrest, que já vem “nativos” no MockitoPP.


Ficaram de fora da análise alguns frameworks que ainda não experimentei, mas parecem interessantes: M0cxx0r e MockItNow. Caso você conheça algum outro, por favor deixe seu comentário.

quarta-feira, 4 de março de 2009

Qt com licença LGPL

A Nokia decidiu permitir a adoção da Lesser General Public License (LGPL) versão 2.1 opcionalmente à GPL 3 para seu framework de construção de interfaces gráficas para desktop e dispositivos portáveis, o Qt. A Qt 4.5, liberada ontem, já saiu com esta licença.

Na prática, significa que a versão do framework poderá ser usada para fins comerciais e assim mais pessoas e empresas se interessarão a investir no desenvolvimento do framework, ganhando tanto a comunidade quanto a Nokia, que poderá incorporar as novidades e correções à sua versão paga.

googleearth

Google Earth, uma das diversas aplicações que usam Qt

Veja também:anúncio da Nokia sobre a liberação do Qt como LGPL.

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() );
}

sábado, 13 de dezembro de 2008

Google Mock

A Google liberou seu C++ Mock Framework sob a nova licensa BSD, complementando seu Google C++ Testing Framework (ou somente Google Test). Ao que me parece, eles fizeram um trabalho bem completo, deixando o framework flexível e fácil de usar.

O Google Mock é baseado no EasyMock, no jMock e no Hamcrest, sendo construído para C++ sob o Google Test. Para utilizá-lo você precisará, além do Google Test que já vem incluso, da std::tr1::tuple, encontrada em algumas implementações de novos compiladores e na boost. Por enquanto ele está acoplado ao Google Test, mas há planos de retirar esta dependência.

Já vinha utilizando o MockPP e vendo o Google Mock tenho a impressão de seu uso ser um pouco mais simples. Assim que tiver um tempo (coisa rara), vou analisá-lo melhor e fazer uma breve comparação, talvez postando-a aqui no blog.

Mais informações sobre o Google Mock aqui.

sábado, 6 de dezembro de 2008

Funcionamento dos frameworks xUnit - Parte 1/2

Durante a série de artigos sobre TDD, tenho citado o uso de frameworks de testes unitários baseados na JUnit. Os exemplos que serão exibidos durante a série partem do princípio que o leitor conhece o funcionamento de um framework xUnit.
Sendo assim, coloco aqui uma explicação breve sobre a estrutura da maioria destes frameworks, de forma a facilitar o entendimento dos próximos artigos.


Os chamados frameworks xUnit surgiram do framework SUnit, construído para a linguagem Smalltalk, por Kent Beck e Erich Gamma. A partir daí, o framework foi portado para diversas linguagens (é praticamente certa a existência de um framework para a sua linguagem favorita) e sua adoção cresceu exponencialmente, sobretudo por projetos que adotaram TDD (como a maioria dos projetos XP).

Idéia

A idéia do framework é facilitar a criação, agrupamento e execução de testes unitários, permitindo sua automatização e a aplicação de seus conceitos. Como seu uso, podemos executar, de uma só vez, os seguintes testes:
  • Teste unitário: verifica se cada pequena parte do programa funciona corretamente.
  • Teste de integração: verifica se as partes do programa funcionam corretamente quando utilizadas conjuntamente.
  • Teste de regressão: verifica se uma alteração numa parte do programa afeta o funcionamento de outras partes, inclusive as não relacionadas diretamente.
Ao permitir executar estes testes de forma simples e rápida, sua adoção como parte do processo de construção do programa se torna indolor. Por exemplo, a execução dos testes pode ser feita após cada linkagem do programa, de forma automática, bastando configurar a ferramenta que gerencia o processo de compilação e linkagem para executar os testes ao final.

Com isso refatoração de partes do código se torna muito mais segura e quaisquer falhas no código são detectadas imediatamente, dando um feedback rápido para o desenvolvedor.

Funcionamento Básico

Um projeto de testes baseado na xUnit, poderá exibir sua saída em modo gráfico ou em modo texto, dependo de sua implementação padrão. A maioria gera saída em modo texto, mas em quase todos existem implementações de saídas em modo gráfico que podem ser adquiridas gratuitamente pela Internet.

O framework funciona a partir da criação de um grupo de testes e da execução dos testes nele contidos. Dentro deste grupo de testes, é permitido adicionar, além dos testes, outros grupos. Ao disparar o método que executa os testes contidos em um grupo, ele executará seus testes e solicitará aos seus subgrupos que também executem seus próprios testes. Assim, todos os testes da hierarquia serão executados. No ponto de entrada do programa, como uma função main, geralmente haverá um grupo de testes principal que iniciará todo o processo.

Como funciona um teste

Cada teste criado deve fazer uma verificação sobre o estado ou comportamento de um determinado código. Nas xUnits, essa verificação é feita utilizando métodos ou macros do tipo assert, que, em sua maioria, recebem uma variável booleana como parâmetro e lançam uma exceção caso o valor da variável seja falso. A exceção dá informações adicionais, como o número e o conteúdo da linha de código onde estava sendo chamado o assert. Por exemplo:

assert( 1 > 2 );

Como o resultado da condição é false, uma exceção é lançada informando algo como "Exceção lançada na linha 1. Condição não cumprida: 1 > 2".

Cada método deverá verificar uma e só uma funcionalidade, que poderá compreender em um ou mais asserts. Por exemplo:

void CalculaMaiorDeDoisCorretamente()
{
assert( 2 == MaiorDeDois( 1, 2 ) );
assert( 0 == MaiorDeDois( 0, 0 ) );
assert( -1 == MaiorDeDois( -1, -2 ) );
}
O teste verifica se a função MaiorDeDois funciona com esperado. Caso algum assert falhe, é exibida a linha de código com a expressão que falhou, como descrito no exemplo anterior.

Originalmente, em praticamente todas as linguagens, um assert interrompe a execução do programa gerando um erro, que decreve a condição não cumprida. Para que o assert não funcione desta maneira, os frameworks geralmente criam um novo assert, como sendo um método da classe de teste a qual herdamos. Esta lança uma exceção ao invés de interromper a execução do programa.

Onde são colocados os testes

Cada teste deve ser colocado em um grupo de testes, que é chamado formalmente de Suíte de Testes (Test Suit). Geralmente nos frameworks xUnit, existe uma classe chamada TestSuit que será como uma lista de (ponteiros para) métodos de teste que você escreverá.
Você deverá adicionar (o endereço de) cada método de teste que você escrever à um objeto de TestSuit. Posteriormente, ela poderá executar todos os métodos que você adicionou - um após o outro. Havendo algum assert dentro deles que não teve sua condição satisfeita, o programa termina com uma exceção (conforme descrito acima).

Na verdade, os métodos que você criou não poderão ser adicionados diretamente no TestSuite. Ao invés disso, você deve criar um objeto de uma classe chamada TestCaller (a "chamadora do teste") que terá o nome do teste e um ponteiro para (o endereço d)ele. Algo como:

TestCaller< MinhaClasseTeste > *chamadaTeste =
new TestCaller< MinhaClasseTeste >(
"NomeDoSeuMetodoDeTeste",
&NomeDoSeuMetodoDeTeste
);

Para simplificar este código, é preferível declarar um tipo que mapeie o TestCaller ao tipo de nossa classe:

typedef TestCaller< MinhaClasseTeste > Chamada;

Agora, substituindo no código anterior, fica:

Chamada *chamadaTeste = new Chamada(
"NomeDoSeuMetodoDeTeste", &NomeDoSeuMetodoDeTeste
);

Agora, para criarmos nossa Suíte de Testes, faremos:

Test* MinhaClasseTeste::suite()
{
Test *suite = new TestSuite( "MinhaClasseTeste" );

Chamada *chamadaTeste = new Chamada(
"NomeDoSeuMetodoDeTeste", &NomeDoSeuMetodoDeTeste
);
suite->addTest( chamadaTeste );

// Ou adiciona diretamente, como neste outro metodo
suite->addTest( new Chamada(
"MeuOutroMetodoDeTeste", &MeuOutroMetodoDeTeste
) );

return ( suite );
}

Existe uma classe chamada TestCase, que agrupa logicamente testes que verificam o comportamento de uma determinada funcionalidade. Ela possui um construtor que recebe uma string que representa o nome do caso de teste, para facilitar sua identificação, os métodos setUp e tearDown para implementação de fixtures, além de um método estático (para quem não conhece métodos estáticos, pense somente como se fosse um método que você pode acessar sem precisar instanciar um objeto da classe) chamado suite, que retorna um (objeto de) TestSuite - o objeto que conterá os nossos testes.
Quando precisarmos criar nossos testes, podemos criar uma classe filha de TestCase. Ela conterá todo o comportamento necessário para a execução de testes e nossos métodos de teste, com seus asserts.

Exemplo prático

Assim, para criar um novo caso de teste chamado TesteContaBancaria, faremos:
  1. A declaração da classe como filha de TestCase;
  2. A declaração nossos testes, preferencialmente na parte privada da classe, pois os mesmos não serão acessados por outras classes;
  3. A implementação dos testes;
  4. A implementação de um método estático suite que criará um TestSuite e adicionará à ele (o endereço de) todos os nossos testes;
Os métodos setUp e tearDown não precisam ser implementados, a menos que você precise fazer um fixture (que veremos mais tarde).

class TesteContaBancaria : public TestCase
{
public:
TesteContaBancaria(std::string nome);

// Suite de testes
static Test* suite();

private:
// Metodo de teste
void ContaTransfereCorretamente();
};


TesteContaBancaria::TesteContaBancaria(
std::string nome
) : TestCase( nome ) // Chama o construtor de TestCase
{
}


Test* TesteContaBancaria::suite()
{
// Cria a suite de testes
Test *suite = new TestSuite( "TesteContaBancaria" );

typedef TestCaller< TesteContaBancaria > Chamada;

// Adiciona o metodo ContaTransfereCorretamente para
// ser chamado pela suite
suite->Add( new Chamada(
&ContaTransfereCorretamente,
"ContaTransfereCorretamente"
));

return ( suite );
}


void TesteContaBancaria::ContaTransfereCorretamente()
{
ContaBancaria minhaConta, suaConta;

minhaConta.DefinirSaldo( 1000.00 );
suaConta.DefinirSaldo( 0.00 );
minhaConta.Transferir( suaConta, 400.00 );

CHECK_EQUALS( 400.00, suaConta.Saldo() );
CHECK_EQUALS( 600.00, minhaConta.Saldo() );
}


Obs: A macro CHECK_EQUALS aqui foi criada sobre assert, e recebe o valor esperado e o valor atual. Se os valores diferirem, uma exceção será lançada. Existem diversas outras macros disponíveis para auxiliar na verificação de estados, dependendo da linguagem utilizada.

Repare que o método de teste ContaTransfereCorretamente é privado. Isto se deve ao fato que ele nunca será acessado diretamente fora da classe e também não se espera que a classe de teste tenha filhas, que irão chamar o método diretamente. Assim, costuma ser um padrão de TDD colocar os métodos de teste como sendo privados.

Este é o funcionamento básico de um framework xUnit. Na parte 2 irei expor o uso de fixtures e mostrarei outros métodos/macros úteis para as verificações de estado. Até lá.