Um dos grandes problemas do javascript é a falta de testabilidade. Vou mostrar aqui nesse artigo uma forma que encontrei de testar as funções de arquivos javascripts utilizando o JUnit. Ah! Claro, isso só é possível se você estiver utilizando o Java 6, que possui suporte a linguagens de script e já vem nativamente com suporte a javascript.
Primeiro criamos o arquivo funcoes.js contendo uma função para validar um determinado formulário. O objetivo é retornar verdadeiro se todos os campos estiverem preenchidos e falso no caso contrário. O formulário html deve ter dois campos: nome e senha. Inicialmente deixaremos essa função sem nenhum código, pois criaremos os testes primeiro:
function validaFormulario(f)
{
return false;
}
Em seguida criamos uma classe para realizar os testes unitários contendo o método testValidaFormulario e outras duas classes internas para servir de Mock do formulário html e dos campos do formulário, HtmlFormMock e HtmlFieldMock respectivamente. Segue o código:
package junit.script;
import junit.framework.TestCase;
public class FuncoesTest extends TestCase
{
public void testValidaFormulario() throws FileNotFoundException, ScriptException, NoSuchMethodException
{
//Aqui entrarão os testes
}
public class HtmlFormMock implements Serializable
{
public HtmlFieldMock nome = new HtmlFieldMock();
public HtmlFieldMock senha = new HtmlFieldMock();
}
public class HtmlFieldMock implements Serializable
{
public String name;
public String value;
}
}
No método testValidaFormulario da classe de testes começamos então importanto o script funcoes.js, e criando um Invocable para poder executar funções no javascript:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
engine.eval( new FileReader( "C:/Projetos/testes/web/funcoes.js" ) );
Invocable invocable = (Invocable) engine;
Em seguida preenche-se o Mock de formulário da seguinte forma:
HtmlFormMock f1 = new HtmlFormMock();
f1.nome.name = "nome";
f1.nome.value = "Tiago";
f1.senha.name = "senha";
f1.senha.value = "123456";
Tendo o invocador de funções de script (Invocable) e o objeto mock, basta alterar os atributos deste objetos para utilizá-lo como parâmetro do formulário por diversas vezes. Veja abaixo os testes que defini para esta função, repare que fiz dois testes para verificar se o campo "nome" e o campo "senha" existem no formulário, pois é possível que criem um formulário html sem o campos:
//Todo formulario preenchido
Boolean b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertTrue("Formulario todo preenchido deve retornar true", b.booleanValue());
//Senha preenchida com nulo
f1.senha.value = null;
b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertFalse("Senha preenchida com nulo deve retornar falso", b.booleanValue());
//Senha preenchida com vazio
f1.senha.value = "";
b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertFalse("Senha preenchida com vazio deve retornar falso", b.booleanValue());
//Nome preenchido com nulo
f1.senha.value = "outra";
f1.nome.value = null;
b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertFalse("Nome preenchido com nulo deve retornar falso", b.booleanValue());
//Nome preenchido com vazio
f1.nome.value = "";
b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertFalse("Nome preenchido com vazio deve retornar falso", b.booleanValue());
//Campo nome do formulario nao existir deve retornar falso
f1.nome = null;
b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertFalse("Campo nome do formulario nao existe entao deve retornar falso", b.booleanValue());
//Campo senha nao pode ser nulo
f1.nome = new HtmlFieldMock();
f1.nome.name = "nome";
f1.nome.value = "Tiago";
f1.senha = null;
b = (Boolean) invocable.invokeFunction("validaFormulario", new Object[] { f1 } );
assertFalse("Campo senha do formulario nao existe entao deve retornar falso", b.booleanValue());
Executando esse teste com o JUnit teremos uma falha logo no primeiro teste, pois o este espera que haja um retorno de true e nossa função javascript está sempre retornando false. Alteremos então a função javascript dando-lhe um código aceitável:
function validaFormulario(f)
{
if( f.nome && f.nome.value && f.nome.value.length() > 0 &&
f.senha && f.senha.value && f.senha.value.length() > 0 )
{
return true;
}
return false;
}
Pronto, tendo a função javascript codificada, basta rodarmos o teste no JUnit novamente para verificar que finalmente a função está funcionando de acordo com o específicado. E o melhor, sempre que ocorrer uma alteração no código dela, saberemos se houve alguma quebra de contrato.
Também é possível testar métodos de classes javascript. Basta utilizar o método invokeMethod da interface Invocable, ao invés de invokeFunction. Mas isso eu deixo pra outro artigo.