quinta-feira, 20 de dezembro de 2007

Seja "descuidado" com seus testes

Primeiramente, perceba que o "descuidado" está entre aspas(" "), com isso quero dizer que ele tem uma razão de existir, e que, óbvio, você não deve negligenciar seus testes.

Me refiro a ser descuidado com "verificações" que fazemos para evitar exceções, como:

- verificar se um objeto é null, para não dar NullPointerException;
- no caso de um Array, verificar se existem elementos antes de tentar pegar a posição 0 ou 1 ou qualquer outra;
- verificar divisões por zero;
- problemas com cast;
- e outros.

Bem, listei acima os que me vieram a cabeça no momento, mas, com certeza, existem muitos outros.

A dica que quero deixar é que abuse dos testes sem fazer "qualquer" dessas verificações, um teste feito com esse "descuido" pode capturar erros que precisariam de várias verificações para serem encontrados. Esses cuidados devem ser tomados no código do seu método (funcionalidade).

Claro que você pode criar métodos que esperam uma exceção, e isso deve ser verificado com maior zelo, mas se este não é o objetivo, e exceções são eventuais, seja "descuidado".

quarta-feira, 19 de dezembro de 2007

Como testar um Método Privado?

Pra começar, surgem duas perguntas:

Devo Fazer? Como devo fazer?

A primeira resposta é: Claro que sim, se ele pode quebrar, ele deve por motivo óbvios, e se não pode quebrar, ele deve por motivos estratégicos.

A segunda resposta é: Aí depende. Depende da linguagem, da capacidade do desenvolvedor, do tempo, "beleza" do código, facilidade de manter, etc.

Pra tentar deixar mais claro, vamos considerar duas possibilidades:

- Testar Explicitamente o método privado;
- Testar por intermédio de outro método.

A primeira possibilidade, testar explicitamente, pode-se fazer duas coisas (que me vem a mente, mas podem existir outras):

- Você pode trocar a visibilidade do método para public com Reflection, em tempo de execução;
- Alterar o método para protected. Isso é mais complicado, em casos de código legado ou sistemas de outros.

A segunda possibilidade, a que prefiro, é usar outro método "testável" para testar o método privado.

Na prática, é muito fácil perceber isso, mas vai que você quer entender logo o que estou falando, então vai um exemplo:


Tenho uma classe com um método public (que retorna uma String) e um private, o método private (criptografa a palavra blablabla)

 0: public class ClassePeba {
1: public String getAlgo(int i)
2: {
3: String palavra = "blablabla";
4: palavra = criptografaPlavra(palavra, i);
5: return palavra;
6: }
7:
8: private String criptografaPalavra(String palavra,
9: int i) {
10: if(i == 1)
11: {
12: palavra = palavra.replace("a", "@");
13: palavra = palavra.replace("b", "!");
14: palavra = palavra.replace("l", "?");
15: }else{
16: palavra = palavra.replace("a", "*");
17: palavra = palavra.replace("b", "$");
18: palavra = palavra.replace("l", "%");
19: }
20: return palavra;
21: }
22: }
O método private (criptografaPalavra) será testado por intermédio do método public getAlgo
Veja os comentários no código:
 0: public class TestClassePeba {
1:
2: ClassePeba classePeba;
3:
4: @Before
5: public void prepare()
6: {
7: classePeba = new ClassePeba();
8: }
9:
10: @Test
11: public void testGetAlgo()
12: {
13: //fazendo este teste, o método getAlgo
14: //já está 100% coberto
15: assertEquals("!?@!?@!?@", classePeba.
16: getAlgo(1));
17: //fazendo este teste, o método
18: //criptografaPalavra também fica 100% coberto
19: assertEquals("$%*$%*$%*", classePeba.
20: getAlgo(2));
21: }
22: }
Acho que fica claro o motivo pelo qual, considero esta abordagem a mais indicada, ela é mais simples, fácil de implementar e de manter, e não a considero nem um pouco deselegante.

ps. Por favor, não reparem o método de criptografar, criei só pra demonstração.

CruiseControl - Automatizando minha Integração Continua

Ouvi muito se falar de CruiseControl, até mesmo aqui na empresa já estudamos a sua viabilidade. Mas, o que eu ganho com isso?

Uma integração "simples": test, backup, update, test, commit, pode ser executada com um botão ao lado do commit, então não dou "cliques a mais".

Mas lá vem uma vantagem, não preciso esperar a integração acontecer, sendo que ela pode demorar um pouco, aqui na empresa ela dura mais ou menos 5 minutos.

E como ouvi alguem me dizer, "sua maior força é sua maior fraqueza", então: a vantagem descrita acima acarreta no maior defeito, em minha opinião, de Automatizar a minha Integração Contínua, o feedback rápido é perdido.

Eu posso configurar o CruiseControl para me avisar mais rapidamente, posso saber 1 minutos após dar um erro, porém, mas se você estiver fazendo a integração "na mão" e o erro acontecer, você o corrigirá imediatamente.

E caso o gerente receba um email que a integração quebrou, duvido que ele diga, "parem o que esta sendo feito e verifiquem a integração".

Pior que isso, mesmo que o gerente peça para corrigir, é que se duas pessoas jogarem erros que provoquem "quebra" na integração, a pessoa que for corrigi-la pode conhecer apenas um dos erros e a demora para a correção desses erros é maior que seria caso a Integração fosse feita "na mão".

A dificuldade de correção pode acarretar num grande problema, o repositório pode ficar muito tempo quebrado.

O Vinícius da ImproveIT escreveu num post sobre Barrigas Abertas a seguinte frase: "Nos projetos que eu conheci, que utilizavam CruiseControl, era comum o repositório estar quebrado.", isso já me parece motivo suficiente para não usar essa Automatização.


Dois bons links sobre Integração Contínua e CruiseControl:

http://www.improveit.com.br/xp/praticas/integracao
http://weblogs.pontonetpt.com/contracorrente/posts/2008.aspx

terça-feira, 18 de dezembro de 2007

Livros sobre Testes (em inglês)

Muita gente procura referencias para estudar testes, e numa lista de discussão sobre Java indicaram o site flazx.

Como não me pareceu pirataria, até por ter o link para comprar na Amazon e tal, listei aqui em baixo, alguns livros sobre testes que tratam de assuntos bem interessantes:

http://www.flazx.com/ebook2330.php
http://www.flazx.com/ebook2721.php
http://www.flazx.com/ebook4275.php
http://www.flazx.com/ebook8592.php
http://www.flazx.com/ebook2630.php
http://www.flazx.com/ebook1369.php

Com as férias chegando, esta é uma boa oportunidade para aperfeiçoar, aprender ou conhecer algo mais sobre testes.

* Também é uma boa oportunidade de estudar Inglês.

Valeu a dica, Barroso.

TDD - Auxiliando a desenvolver consultas com Hibernate + Spring

Quando usamos sql "puro", testar uma consulta é muito simples de ser feito, pois podemos utilizar uma ferramenta de BD como o MySQL Admin, ou PGAdmin, porém quando usamos APIs de Persistência, o problema aparece.

Esses dias, num caso de uso que necessitava de uma consulta nem tão complexa, tive que startar e re-startar o servidor de aplicação 8 vezes, para testar a consulta que era montada.

Daí, fiquei pensando se TDD poderia me ajudar, e ví que ele pode me ajudar e muito.

Usando TDD para o desenvolvimento de uma consulta, além de diminuir o tempo perdido com o servidor de aplicação sendo levantado e derrubado várias vezes, ainda ganho o tempo de abrir a aplicação, preencher campos (como um filtro por exemplo) e submeter um formulário.

Para fazermos TDD com consultas, precisamos gerenciar as transações para garantir que determinadas informações estarão na base de dados e outras não sejam persistidas.

Utilizando Hibernate + Spring precisamos extender a classe AbstractTransactionalSpringContextTests do Spring, para gerenciar as transações.

extends AbstractTransactionalSpringContextTests

No método de testes devemos escrever o método getConfigLocations para carregar os arquivos de contexto do Spring:
0: @Override
1: protected String[] getConfigLocations()
2: {
3: setAutowireMode(AUTOWIRE_BY_NAME);
4: return new String [] {"applicationContext*.xml"};
5: }
No método de teste, você insere registros para simular um banco de dados populado:
 0: public void testGetAvisosMesAno()
1: {
2: Aviso a1 = new Aviso();
3: a1.setId(1L);
4: a1.setData(new Date(107, 11, 1));
5:
6: Aviso a2 = new Aviso();
7: a2.setId(2L);
8: a2.setData(new Date(107, 10, 1));
9:
10: Aviso a3 = new Aviso();
11: a3.setId(3L);
12: a3.setData(new Date(107, 11, 20));
13:
14: avisoDao.save(a1);
15: avisoDao.save(a2);
16: avisoDao.save(a3);
17:
18: Collection avisos = avisoDao.
19: getAvisosMesAno(new Date(107, 11, 1),
20: new Date(107, 11, 30));
21: assertEquals(2, avisos.size());
22: }
Se já existirem dados no banco, o tamanho do retorno (avisos.size()) não é um bom teste, é melhor verificar se os elemento que deseja, estão lá, e se os que não deseja, não estão.


A lição que deve ser deixada é que TDD é tão ou mais útil para um método de persistência do que para um método de negócio.
O "ou mais" é o que acho que se encaixa melhor, pois imagine a possibilidade de errar na criação de uma consulta, além de tudo, usamos muito "palavras" que não são compiladas, como o nome de campos da sua classe.

Outra dica é que mesmo usando SQL puro, o TDD pode conduzir muito bem a construção da sua query, e acho que mesmo sendo fácil testar a consulta com outras ferramentas, o TDD pode trazer mais benefícios do que, simplesmente, testar a consulta.
Veja também o post sobre 100% de Cobertura.

sexta-feira, 14 de dezembro de 2007

JMockit - Mockando um Método Estático

É com grande felicidade que consegui, nesta manhã de sexta, mockar um método estático, p&#@ que p@$%&, sensacional.

O nome do cara é JMockit

Bem, o meu exemplo é bem simples:

Criei uma classe que tem somente um método estático, é esta classe que quero mockar:
0: public class ClasseUtil {
1: public static int metodoEstatico()
2: {
3: return 1;
4: }
5: }
Então, uma classe que utiliza este método:
0: public class ClasseFuncionalidade {
1: public static int metodoLocal()
2: {
3: return ClasseUtil.metodoEstatico();
4: }
5: }
Por fim, a classe de teste:
 0: public class ClasseFuncionalidadeTeste{
1:
2: public static class MockClasseUtil{
3: public static int metodoEstatico()
4: {
5: return 0;
6: }
7: }
8:
9: @Before
10: public void prepare(){
11: Mockit.redefineMethods(
12: ClasseUtil.class,
13: MockClasseUtil.class);
14: }
15:
16: @After
17: public void finalize(){
18: Mockit.restoreAllOriginalDefinitions();
19: }
20:
21: @Test
22: public void metodoLocal(){
23: assertEquals(0, ClasseFuncionalidade.
24: metodoLocal());
25: }
26: }
Perceba que criei uma outra classe (inner class) chamada MockClasseUtil, com um método (metodoEstatico) de mesma assinatura do método da classe ClasseUtil, porém o retorno é diferente (No original é 1 e no falso é 0).

Redefino os métodos da classe real pelos da classe mock:
0: @Before
1: public void prepare(){
2: Mockit.redefineMethods(
3: ClasseUtil.class,
4: MockClasseUtil.class);
5: }
Se fosse no JUnit3, poderia usar o método setUp para invocar o redefineMethods.

E para voltar "ao normal":
0: @After
1: public void finalize(){
2: Mockit.restoreAllOriginalDefinitions();
3: }
A única dificuldade foi "ver" que o comando "-javaagent:jmockit.jar" deve ser passado como parâmetro para a JVM:

No eclipse é só fazer isso, na hora de rodar o teste:



ou isso, para rodar com test suite ou qualquer outro lugar:

quinta-feira, 13 de dezembro de 2007

JUnit4 - Suite de Testes

Para provar, ainda mais, que o JUnit4 veio "apaixonado" por annotations, lá vai mais uma da série: JUnit4 - Novidades e Melhorias.

Vou mostrar um exemplo de TestSuite nas duas versões, isso tornará a explicação clara:


Para criar uma suite de testes com JUnit3:

 0: public class AllTests extends TestSuite
1: {
2: public static TestSuite suite()
3: {
4: TestSuite suite = new TestSuite();
5:
6: suite.addTestSuite(ClasseFuncionalidadeTeste.class);
7: suite.addTestSuite(CopyOfClasseFuncionalidadeTeste.
8: class);
9: }
10: }
Agora, com JUnit4:

0: @RunWith(value=Suite.class)
1: @SuiteClasses(value={
2: ClasseFuncionalidadeTeste.class,
3: CopyOfClasseFuncionalidadeTeste.class
4: }
5: )
6: public class TestAll {
7: }
Bem, com JUnit4, a classe "suite" só existe para "receber" a annotation e ser executada, não necessitando de nenhum método.

segunda-feira, 10 de dezembro de 2007

JUnit4 - Novidades e Melhorias

Neste fim de semana estava trabalhando em uma aplicação pessoal e tentei usar o JUnit4 para criar meus testes.

Primeiro que tive uma surpresa ótima, os meus métodos de teste criados para JUnit3 funcionam no JUnit4.

O JUnit4 veio com uma aplicação muito forte de Annotations, irei listar as que vi e percebi serem de maior importância:

@Test - O JUnit4 somente necessita da annotation @Test para identificar um método de teste.
@Before e @After - Outras novidades são as annotations @Before e @After, como o nome já diz, são métodos invocados antes e depois dos métodos de teste.

Ainda sobre a annotation @Test, esta recebe parâmetros e 2 que descobri são realmente incríveis:

expected - este parâmetro serve para testar Exception, somente é necessário informar na annotation qual Exception é esperada e pronto: @Test(expected=IOException.class).
timeout - este serve testar tempo de execução do teste, onde o teste falha se demorar mais que o tempo informado: @Test(timeout=2000).

Com JUnit4, uma classe de teste não extende TestCase e seus métodos não precisam começar com "test", como já foi dito, usa-se @Test.

Foram adicionados 2 novos asserts:

O assertEquals com um par de arrays que podem ser passados como parâmetro, desta forma o método verifica cada elemento: assertEquals(Object[] o1, Object[] o2);
E o assertEquals que recebe um primeiro parâmetro String e um par de arrays, este primeiro parâmetro aparece ao lado do erro, caso o teste falhe, permitindo a identificação da linha exata onde o teste falhou: assertEquals(String message, Object[] obj1, Object[] obj2);

Um exemplo básico e que mostra o que deve ser feito para que sua classe de teste feita em JUnit3 se adeque a nova versão do JUnit:
 0: //Com JUnit3
1: public class HelloWorld extends TestCase
2: {
3: //necessita do prefixo "test"
4: public void testSoma()
5: {
6: // Testa se 1+1=2:
7: assertEquals (2, 1+1);
8: }
9: }
10:
11: //Com JUnit4
12: public class HelloWorld //Não extend TestCase
13: {
14: @Test
15: //não precisa ter este nome, poderia ser soma()
16: public void testSoma()
17: {
18: // Testa se 1+1=2:
19: assertEquals (2, 1+1);
20: }
21: }

sexta-feira, 7 de dezembro de 2007

100% de Cobertura - Até quanto isso é importante?

Existe um embate violento sobre este assunto, outro dia participei de uma discussão na xp-rio (ótima lista de discussão sobre XP), com alguns feras do XP no brasil sobre isso. Bem, é certo que fazer testes é importante, mas devo usar a métrica de 100% de cobertura?

Vi várias opiniões, a minha começou com: "Só devo cobrir os métodos mais complicados", depois ouvi uma boa argumentação que me fez pensar assim: "Só devo cobrir o que pode quebrar". Desta forma, um método que apenas chama outro, não terá nenhum teste. Mas ele precisa?

Prefiro dizer que ele "não precisa", pois se algo fizer este método quebrar, o compilador me avisa.

Então, conversando com o Tales (meu gerente e figura conhecida no meio ágil), percebi a necessidade de garantir a qualidade para o cliente, como nos métodos tradicionais é usado um CMMI ou MPS-Br ou ISO, as metodologias ágeis são carentes nessa área e vez por outra precisam de alguma métrica para mostrar a qualidade, e na minha opinião, ter 100% de linhas de código cobertas por testes, me garante MAIOR qualidade num produto do que CMMIs ou ISOs da vida.

Por fim, este argumento não pôde ser rebatido, sabemos que testes são bons, e que se iremos perder 10 minutos, ou menos, fazendo um teste que nunca irá quebrar, e que será, no mínimo, parte de uma métrica de qualidade, por que não fazê-lo?

Que fique claro que não concordo que um "teste ruim" seja melhor que não ter teste. Mas isso fica pra outra blogada.

quinta-feira, 6 de dezembro de 2007

JMock versus Classes Concretas 2 - A Missão

Me recuperando da decepção da incompatibilidade de versões do JMock, ví que o JMock 1 pode mockar classes concretas.

Baixei o jmock-cglib-version.jar, e fiz como diz no link abaixo:

http://www.jmock.org/jmock1-cglib.html

e funcionou.

A única limitação é que não pode ser uma classe final.



JMock acaba de recuperar seus pontos.


Thanks, Nat Pryce.

quarta-feira, 5 de dezembro de 2007

TDD - Um exemplo prático

No início, via sempre o exemplo de validação de cpf, as vezes me pegava pensando, será que pra casos "não matemáticos" isso vai funcionar?

Hoje, no trabalho, desenvolvendo um método bem simples, resolvi tirar os "print screen" pra postar aqui e mostrar pros iniciantes em TDD que o assunto em bem próximo da nossa realidade.

Segue o exemplo abaixo:

Dada uma Collection de AtoNormativo* e um objeto do tipo AtoNormativo, façamos um método que retorne a Collection de AtoNormativo excluindo o objeto passado.
*AtoNormativo é uma classe e tem uma propriedade Long id.

1) Crio o método retiraNorma passando uma Collection e um AtoNormativo;




2) Crio o método testRetiraNorma, crio a Collection, adiciono 3 objetos do tipo AtoNormativo e chamo o método retiraNorma, passando um dos objetos inseridos, para ser retirado da Collection.



Perceba que após chamar o método, testo se a Collection foi retornada com 2 elementos somente, se um objeto que não deve ter sido removido, não foi removido, e se um objeto que deve ter sido removido, foi removido.


3) Rodei o teste e deu erro. É o que deve acontecer, já que o método ainda retorna Null.
Implemento o método.




4) Rodo o teste e tudo ok.



A barra verde no canto esquerdo superior da imagem é o sinal de sucesso.

Pronto.


Perceba que a sequência lógica se mantém, penso no que vou fazer, penso no que o método deve fazer, implemento e testo, porém, quando o teste é rodado, você não precisa mais rodar a aplicação, abrir uma determinada tela e executar um certa funcionalidade, o teste garante que, na situação que você pensou, o método irá funcionar.

Perceba que o teste pode ser alterado, podem ser inseridos situações em que o objeto passado não está dentre os objetos da Collection, e isso pode ser feito, o teste não é final, ele sempre pode evoluir.

TDD - Desenvolvimento Orientado a Testes

Quando ouvi a primeira vez sobre Test Driven Development achei imoral, o quão ridículo pode parecer fazer testes antes de desenvolver uma funcionalidade?

Bem, o negócio não é tão feio quanto parece, fazer TDD te ajuda em muita coisa.

Outro dia eu estava fazendo um Caso de Uso relacionado a uma loja virtual, onde deveria retornar vários valores de acordo com os produtos comprados.

Comecei fazendo o Teste:

Primeiro Passo: Gerei a classe de teste e criei somente a assinatura do método.
Segundo Passo: Fiz as simulações necessárias numa calculadora e amarrei no teste, de acordo com a entrada a saída deveria ser... Óbvio que o teste ainda não funcionava.
Terceiro Passo: Parti para a implementação, encontrei menos dificuldades do que imaginava, a lógica estava na minha cabeça, e quando imaginei ter terminado a funcionalidade, simplesmente rodei o teste.

Corrigindo os erros que encontrei no teste e corrigindo o próprio teste, terminei a funcionalidade num tempo muito próximo ao tempo que faríamos sem teste, e o melhor é que a funcionalidade já estava testada, nem precisei abrir a tela pra testar cada situação.

Confesso que existem alguma situações que o TDD não ajuda muito, como por exemplo, num método que somente chama outro método, nesses casos, eu prefiro varrer a classe após a implementação e fazer os testes que faltaram.

Abuse do artifício dos Mock Objects, e experimente o TDD, os seus DEBUGs vão ser menos constantes e você terá a sensação de Casos de Uso concluídos de verdade.

Vocês não imaginam a sensação que tive quando rodei minha classe de testes (haviam 18 simulações testadas) e a barrinha ficou verde.


ps. uso a primeira pessoa (encontrei, tive, Gerei, etc) mas tudo isso foi feito em dupla.

JMock versus Classes Concretas

O JMock (acho que o EasyMock também) precisa de uma interface para ser instanciado, mas eu precisei usar com uma Classe Concreta.

Sei que a primeira idéia é: "Porque você não cria uma interface?"

No meu caso, até poderia, mas imagine um sistema legado, onde você esteja mantendo, criar uma interface e alterar um monte de classes talvez não seja o ideal.

E isso me motivou a procurar uma solução para este problema, no site do JMock, encontrei uma referencia ao CGLib (links abaixo):

http://www.jmock.org/jmock1-cglib.html
http://www.jmock.org/mocking-classes.html


algumas horas depois...

Nas soluções acima, me parece que só funciona com o JMock 2, e aí vem a notícia mais triste que tive desde que comecei a fazer testes:

Os testes feitos com JMock 1 não rodam se eu mudar o jar do JMock para a versão 2.

Indo no site (http://www.jmock.org/versioning.html) vi isso:


2.0.0 Incompatible API changes, removes API elements deprecated by version 1.2.0.


Bem, pra quem usa JMock 1 e não quer re-fazer TODOS os seus testes, crie uma interface para a classe que será mockada.

O JMock acaba de perder 5 pontos.

terça-feira, 4 de dezembro de 2007

EMMA - Auxiliando na cobertura de testes

Caras,

o EMMA é uma ferramenta incrível para quem quer cobrir sua aplicação por testes, ela consiste em exibir relatórios de cobertura, indicando as linhas que não são cobertas, a porcentagem de cobertura, pacote e tudo mais.

COBERTURA DE TESTES COM EMMA: http://www.improveit.com.br/xp/praticas/tdd/emma


Pra quem usa eclipse, existe um plugin muito show, é o eclEMMA.

http://www.eclemma.org/

Vou mostrar um exemplo de utilização do eclEMMA.

passo 1 (escolho uma classe para ver o quanto e onde ela esta coberta):



passo 2 (seleciono a suite de testes):



Passo 3 (e o resultado de uma classe 100% coberta):



Enquanto lutava para cobrir linhas de código com meus testes, percebi que sem o eclEMMA seria muito mais difícil, por isso, indico fortemente o uso desta ferramenta.

ps. credito a descoberta do plugin ao Igo Coelho, pois não tinha ouvido falar em lugar nenhum e o mesmo me apresentou.

Passagem de parâmetros para método mockado

Bem,

quando você mocka uma classe, você deve informar, no método de teste, o que o método deve fazer, então, vejamos:

classeDao.expects(once()).method("getAlgumaCoisa").
with(eq(1), eq(true)).will(returnValue(obj));

Traduzindo:

A classeDao é um mock, e neste escopo (método de teste), ele será invocado 1 única vez (expects(once())), o método que será chamado é o getAlgumaCoisa (method("getAlgumaCoisa")), quando passar os parâmetros 1 e true (with(eq(1), eq(true))), retorne um Object obj (will(returnValue(obj))).

Simples, porém me deparei com uma situação bem estranha:

O método que eu estava testando, passava como parâmetro a data atual, e não o recebia como parâmetro. Bem, o problema é o fato do método instanciar um objeto e passar como parâmetro para outro método (que iremos mockar).

Vou simplificar com um exemplo:

Na classe classeManager

o metodo fazAlgo():

//faz um blablabla
classeDao.getAlgumaCoisa(new String[]{"1", "2"});
//faz o resto do blablabla

no meu test:

Estou testando a classe classeManager

o método testFazAlgo():

se eu fizer:

classeDao.expects(once()).method("getAlgumaCoisa").
with(eq(new String[]{"1", "2"})).will(returnValue(obj));

não vai funcionar, ele vai me dizer que o método nunca foi invocado.

Pra quem já estudou um pouco de O.O. já deve ter percebido, o objeto que instanciei na classe classeManager (classeDao.getAlgumaCoisa(new String[]{"1", "2"});) é diferente do instanciado na classe de testes (classeDao.expects(once()).method("getAlgumaCoisa").
with(eq(new String[]{"1", "2"})).will(returnValue(obj));).

Então a solução é:

classeDao.expects(once()).method("getAlgumaCoisa").
with(ANYTHING).will(returnValue(obj));

o que quer dizer:

Quando eu passar "Qualquer Coisa" (with(ANYTHING)) para o método getAlgumaCoisa, retorne o obj.

Importante lembrar que a quantidade de parâmetros deve ser igual a do método "de verdade".

segunda-feira, 3 de dezembro de 2007

Quero usar mocks, uso JMock ou EasyMock?

Bem, já vi defensores das duas "ferramentas", eu prefiro o JMock, acho ele muito simples e bem funcional, de qualquer forma, vou colocar aqui os links para download dos dois:

JMock: http://www.jmock.org/
EasyMock: http://www.easymock.org/

Se você quer começar com JMock: http://www.jmock.org/getting-started.html

Pra ver um caso simples das duas formas, isso pode ajudar a escolher: http://blogs.warwick.ac.uk/colinyates/entry/jmock_versus_easymock/

Aqui tem uma tabelinha com algumas diferenças: http://www.tcay.com/dev/JMockVsEasyMock.htm

O que devo saber pra começar a fazer testes?

Inicialmente, aconselho estudar JUnit, que é uma ferramenta excelente para fazer testes unitários em Java e se integra com o Eclipse, Netbeans e qualquer outra IDE que mereça respeito.

Como os casos de uso evoluem e a complexidade dos testes acompanha, aconselho estudar Mock Objects.

Mocks são simulações de objetos, fazendo com que seus testes fiquem presos a um determinado escopo, por exemplo, se você esta fazendo um teste em uma classe de negócio e o método desta classe invoca um método de outra classe que faz uma consulta no banco, você deve usar um Mock para simular o objeto desta outra classe, simulando assim esta consulta, pois a consulta será testada no momento em que o teste para o seu método for criado.

Com isso você pode começar a fazer testes de seus métodos.

No site da ImproveIT existem vários materiais para estudo no assunto, vou linkar aqui em baixo dois textos bem legais:

Um pouco de TDD, é apresentado um exemplo com JUnit: http://www.improveit.com.br/xp/praticas/tdd

Mock Objects, você pode dar uma lida e ter uma boa idéia sobre o assunto: http://www.improveit.com.br/xp/praticas/tdd/mock_objects