quinta-feira, 24 de abril de 2008

EclEMMA e seus problemas com o finally

Hoje tive a maior decepção do ano, logo com o EclEMMA, um plugin que tinha como extremamente confiável.

Para ilustrar o problema vou fazer um exemplo bem simples (desculpem os termos usados, mas estou meio irritado com isso):
0:
1: public class StupidClass {
2:
3: public String falar(){
4:
5: try
6: {
7: System.out.println("oyeah!");
8: }
9: finally
10: {
11: System.out.println("ogou!");
12: }
13:
14: return "oh! fezes";
15: }
16:
17: }
E seu teste:
0: import static org.junit.Assert.assertEquals;
1:
2: import org.junit.Before;
3: import org.junit.Test;
4:
5: public class TestStupidClass {
6:
7: StupidClass stupidClass = null;
8:
9: @Before
10: public void antes(){
11: stupidClass = new StupidClass();
12: }
13:
14: @Test
15: public void blablabla(){
16: assertEquals(stupidClass.falar(), "oh! fezes");
17: }
18:
19: }
Para a minha infeliz surpresa, o corpo do finally não é considerado coberto, na verdade ele é "amarelado".
Pra quem não sabe o que significa o amarelo ou verde ou vermelho, veja aqui.

Agora é buscar outra ferramenta que atenda essa necessidade, quando, e se, achar, posto aqui.

quinta-feira, 17 de abril de 2008

Acessando um método não visível "na marra"

Um dia eu falei que um método privado deveria ser testado por intermédio de outro, já que se não existir um método que o chame, ele nem deve existir. Bem, hoje vi que não é verdade, ou pelo menos encontrei um caso que precisava implementar um método protected em uma classe que seria enviada como parâmetro para outro método.

Aí pensei, "tá na hora de sujar as mãos".

Como é possível que nem todos saibam usar Reflection, vou postar aqui o código para ajudar a quem precisar:

Este é o método:

protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(mailSender.getUsername(), mailSender.getPassword());
}

e assim o acesso:

public void testGetPasswordAuthentication() throws Exception{
Method metodo = authenticatorImpl.getClass().getDeclaredMethod( "getPasswordAuthentication", new Class[]{});
metodo.setAccessible(true);
metodo.invoke(authenticatorImpl, new Object[]{});
}

Boas práticas - Parte II

Uma boa prática que tenho percebido ajudar muito na análise de testes, é o uso do parâmetro (message) do tipo String que todos os asserts do JUnit suportam.
Desta forma indico que sempre este parâmetro seja utilizado.

Exemplos:
assertEquals("Test 1", true, true);
assertTrue("Test 2", false);
assertNotNull("Test 3", new Object());

e todos os outros asserts se comportam da mesma forma.

O erro aparecerá assim: junit.framework.AssertionFailedError: Test 2
Indicando onde o erro aconteceu.

Numa classe de testes onde você tenha muitos assert é quase impossível, ou no mínimo complicado, encontrar em que assert o teste falhou.

quarta-feira, 2 de abril de 2008

BDD - Mais uma técnica de programação?

Behaviour Driven Development é algo que, atualmente, se ouve bastante no meio Ágil, e lendo um artigo do Ivan Sanchez sobre o assunto, vejo que não existem diferenças "em termos de técnica de programação" entre BDD e TDD (Test Driven Development), aparentemente o BDD foi criado para substituir conceitualmente o TDD, pois o termo Test pode ser (e é) facilmente confundindo com Validação e causa uma certa distância entre nós e os humanos normais (não-desenvolvedores).

Segundo o Portal do BDD, esta técnica é a evolução "lógica" do TDD e do Acceptance Test Driven Planning. BDD têm um vocabulário que pode ser utilizado por todos os interessados: empresa, desenvolvedores, testadores, analistas e gerentes. Este vocabulário é tido como o "grande bum" do BDD.

BDD é mais rico que TDD quando pensamos em ferramentas, pois existe um conjunto de frameworks que auxilia na sua implementação, para Java o mais famoso (e o único que eu conheço) é o JBehave.

Vejo BDD como uma idéia bem bacana e que merece ser experimentada, os depoimentos que escuto são sempre positivos.

Desacoplando para melhorar o design e facilitar os testes

Usando TDD, normalmente nos deparamos com situações em que precisamos mudar nossa implementação para atender a algum teste, isso é normal e viável, já que os testes são parte do sistema.

Quando o Paulo Silveira veio a Fortaleza e ministrou um workshop sobre Java, falou-se muito sobre desacoplar, não usar métodos estáticos (sempre que possível) e outras boas práticas como IoC, acontece que venho buscando sempre soluções pra esses casos sem mudar minha implementação, na maioria até consegui, lógico que com maior dificuldade e esforço.

Assim, esta semana discutimos a implementação de alguns testes que estavam muito complicados e ví que o que o Paulo havia falado era bem simples, ao menos da maneira que solucionamos o problema. Vou ilustrar com um exemplo bem simples pra deixar claro como podemos facilitar os testes desacoplando algumas coisas.

Primeiro quero dizer que com um Spring da vida você não vai precisar usar esse artifício, pois com o IoC do Spring você pode fazer isso;
Segundo, é importante ficar atento, porque se existirem muitas dependência, um artifício simples como esse pode não funcionar.

Ao exemplo:

Tenho 3 classes.
0: public class ClasseA {
1: public void metodo1(){
2: ClasseB classeB = new ClasseB();
3: classeB.metodo2();
4: }
5: }
0: public class ClasseB {
1: public void metodo2(){
2: System.out.println(ClasseUtil.m1());
3:
4: ClasseUtil classeUtil = new ClasseUtil();
5: System.out.println(classeUtil.m2());
6: }
7: }
0: public class ClasseUtil {
1: public static String m1(){
2: return "m1";
3: }
4:
5: public String m2(){
6: return "m2";
7: }
8: }
No teste da ClassseB terei algumas dificuldades porque existe uma chamada a um método estático (podemos usar JMockit, porém, dependendo do retorno, torna-se uma tarefa muito complicada) e um instanciamento da ClasseUtil.

Como poderíamos evitar isso? Bem simples:

Passaremos a instância da ClasseUtil como parâmetro do método:
0: public class ClasseA {
1: public void metodo1(){
2: ClasseB classeB = new ClasseB();
3: classeB.metodo2(new ClasseUtil());
4: }
5: }

0: public class ClasseB {
1: public void metodo2(ClasseUtil classeUtil){
2: System.out.println(classeUtil.m1());
3: System.out.println(classeUtil.m2());
4: }
5: }

O design fica bem simples e os testes mais fáceis de implementar.