Wiki

Orientações técnicas/Quando Usar Framework Testes

Table of Contents [-]

    Quando usar cada framework de testes durante o desenvolvimento dos testes unitários ?

    JUnit Para utilização do JUnit integrado ao Eclipse IDE podemos tomar como base o seguinte artigo: 'Como utilizar JUnit com Eclipse'. Além da documentação disponível no próprio site do projeto JUnit. No caso dos projetos utilizando o framework demoiselle, em particular o demoiselle-crud, o JUnit já é disponibilizado juntamente com o framework, o que dispensa sua instalação prévia. Vale como recomendação de boa prática que seja criado um projeto de testes anexo ao projeto em desenvolvimento. Nesse projeto de testes serão incluídos os casos de teste para cada classe desenvolvida no projeto principal. É interessante que dentro do projeto de testes a estrutura de pacotes do projeto principal seja mantida, para facilitar a navegação pelo desenvolvedor. Outra orientação de boa prática é que o nome das classes de teste sejam o mesmo nome das classes a serem testadas, exceto a terminação do nome com a inclusão da palavra Test. Exemplo: classe a ser testada ClasseGenerica.java, classe de testes ClasseGenericaTest.java. Dentro de cada classe de testes é interessante que o nome de cada caso de teste que representará um teste específico para um método da classe principal, seja um nome de faça referência ao nome do método a ser testado e o tipo de teste que está sendo realizado. Exemplo:

    método principal a ser testado: public void insert()
    caso de teste 1: public void testInsert()
    caso de teste 2: public void testInsertNullObject()

    No exemplo acima temos dois casos de testes para o mesmo método insert() da classe principal a ser testada. Fica claro que método está sendo testado e o tipo de teste que está sendo realizado. Outra orientação é a inclusão de comentários no cabeçalho de cada método de testes explicando como o teste será realizado. O JUnit será utilizado para todos os casos de testes do projeto, inclusive os que utilizam o Easymock, Easymock classextendion e o JMockit, ou a combinação deles.

    Easymock No caso das bibliotecas do Easymock existirá um emprego específico do Easymock ou do Easymock Classextension dependendo do foco do teste. Para o caso de haver a necessidade de se mockar uma interface, deverá ser utilizado o Easymock. Já para os casos de haver a necessidade de mockar classes, o classextension será o indicado. A utilização do Easymock em um modo geral será nos casos em que são passadas classes ou interfaces como parâmetros dentro da chamada de métodos das classes sob testes. No caso de serem necessários mocks para classes internas ao método que está sendo testado, o indicado é se utilizar o JMockit para substituir a execução dessa classe. Outro indicador de se utilizar o Easymock é a necessidade de serem mockados somente alguns métodos e seus retornos da classe em questão. O que não acontece com o JMockit quando se trata de interfaces, onde ele força a implementação (ou pelo menos a declaração) de todos os métodos da interface. A utilização do Easymock também é interessante quando se quer definir um valor fixo para o retorno do método que está sendo mockado. Uma limitação para a utilização do Easymock é a impossibilidade de se mockar métodos privados, estáticos e finais das classes. Segue abaixo um exemplo de utilização do Easymock nos testes das classes do demoiselle-crud. A classe sob testes é a MessageDecorator e o método que se deseja testar especificamente dessa classe é o método getLocale() Para essa caso foi criada uma classe CrudMessageDecoratorTest para a realização dos casos de testes. Veja classe abaixo.

    public class CrudMessageDecoratorTest extends TestCase { 
    
    
        private ICrudMessage crudMessage;
    
    
        /**
        *  Initialize test class creating a mock object from ICrudMessage interface	
        */
    
    
        @Before
        public void setUp() throws Exception {
    
    	crudMessage = EasyMock.createMock(ICrudMessage.class);
    	EasyMock.expect(crudMessage.getLabel()).andReturn("myLabel").anyTimes();
    	String key = "crud.message.ok";
    	EasyMock.expect(crudMessage.getKey()).andReturn(key).anyTimes();
    	EasyMock.expect(crudMessage.getCustomPattern()).andReturn(key.replaceAll("crud.", "app.myMB.")).anyTimes();
    	Locale loc = new Locale("pt", "Br");
    	EasyMock.expect(crudMessage.getLocale()).andReturn(loc).anyTimes();
    	EasyMock.expect(crudMessage.getResourceName()).andReturn("META-INF/crud-messages").anyTimes();
    	EasyMock.expect(crudMessage.getAppResourceName()).andReturn("messages").anyTimes();
    	EasyMock.expect(crudMessage.getSeverity()).andReturn(Severity.ERROR).anyTimes();
    
    	EasyMock.replay(crudMessage);
    
        }
    
    
        @Test
        public void testGetLocale() {
            MessageDecorator msgDecorator = new MessageDecorator(crudMessage, "test");
    	Assert.assertEquals("pt_BR", msgDecorator.getLocale().toString());
        }
    
    }

    Notem que no método setUp() da classe de testes foi criado um mock para a interface ICrudMessage utilizando o Easymock. Nele foram ensinados os comportamentos para diversos métodos dessa interface, bem como os retornos esperados. Já no caso de teste testGetLocale() foi passado no construtor do objeto da classe sob testes nosso objeto mock (MessageDecorator msgDecorator = new MessageDecorator(crudMessage, "test");)

    JMockit Como já foi citado anteriormente, a utilização do JMockit se faz interessante quando houver a necessidade de se mockar uma classe que está sendo utilizada internamente ao método da classe sob testes. Ou seja, essa classe não está sendo passada como parâmetro para o método que está sendo testado, porém em um determinado momento de sua execução a chamará, o que por ventura poderá ocasionar um erro dependendo do contexto do teste. Nesses casos o JMockit é recomendado, pois poderemos alterar o comportamento dos métodos que são chamados de classes terceiras que não estão sendo alvo do teste, porém estão dentro do escopo do método da classe sob testes. No caso de uso do JMockit não implica a não utilização do Easymock, pelo contrário, poderemos utilizar um mix das duas soluções em conjunto. Exemplo de utilização do JMockit juntamente com Easymock. A classe sob testes é a ResourceBundleManager e os métodos em testes são getMessage() e getCurrentLoader(). No caso do teste para o getMessage(), internamente a esse método é feito um chamado para o método getCurrentInstance da classe FacesContext. Nesse caso é indicado mockar essa classe e o comportamento do método. Para isso foi utilizado JMokit. Já para se utilizar esse método foi necessário mockar o objeto de retorno do tipo FacesContext. Nesse caso foi utilizado o Easymock para resolver a questão. Veja código abaixo.

    public class ResourceBundleManagerTest extends TestCase {
    
        private ResourceBundleManager bm = null;
    
    
        public static abstract class MockFacesContext
        { 
    
            @Mock
            public static FacesContext getCurrentInstance() {
                 FacesContext ctx = EasyMock.createMock(FacesContext.class);
                 Application app = EasyMock.createMock(Application.class);
                 ELContext ectx = EasyMock.createMock(ELContext.class);
                 ValueExpression vexp = EasyMock.createMock(ValueExpression.class);
                 EasyMock.expect(vexp.getValue(EasyMock.isA(ELContext.class))).andReturn("test");
    
                 EasyMock.replay(vexp);	
                 EasyMock.replay(ectx);
    
                 ExpressionFactory exf = EasyMock.createMock(ExpressionFactory.class);
                 EasyMock.expect(exf.createValueExpression(EasyMock.isA(ELContext.class), EasyMock.isA(String.class),EasyMock.isA(Class.class))).andReturn(vexp);
                 EasyMock.replay(exf);
    
    
                 EasyMock.expect(app.getExpressionFactory()).andReturn(exf);
                 EasyMock.replay(app);
    
                 EasyMock.expect(ctx.getApplication()).andReturn(app);
                 EasyMock.expect(ctx.getELContext()).andReturn(ectx);
                 EasyMock.replay(ctx);
    
                 return ctx;
            }
    
        }
    
        public void setUp(){
            bm = new ResourceBundleManager();
        }
    
        public void testGetMessageFromResourceBundle(){
            Mockit.setUpMock(FacesContext.class, MockFacesContext.class);
            String msg = bm.getMessage("test");
            assertEquals("test", msg);
        }
    
        public void testGetCurrentLoader(){
            NoLayers nl = new NoLayers();
            ClassLoader loader = bm.getCurrentLoader((Object)nl);
            assertNotNull(loader);
        }
    
    }
    0 Anexos
    2510 Visualizações
    Média (0 Votos)
    A média da avaliação é 0.0 estrelas de 5.
    Comentários
    Comentar
    Marcelo Vieira
    Ola!
    Parabéns pela iniciativa.
    Mas permita-me sugerir que considere que os nomes a serem dados tanto para as classes de testes quanto para o método, sejam nomes mais descritivos ao entendimento do processo e operação de negócio-domínio-recurso(técnico) que está sendo implementado.

    Quanto a ficar fácil a associação da classe e método de teste à(s) classe(s) testadas, acredito que resolva-se com a boa contextualização dos mesmos a partir dos namespaces, exemplo:
    - Processo > Operação: "Vendas de Produtos" > "Carrinho de compra".
    - Contexto: Xxxxx.Vendas.Produtos
    - Classe: CarrinhoDeCampra
    - Métodos: EhInseridoMaisDeUmItem_CalculaOValorTotal
    Postado em 27/09/13 10:47.
    Marcelo Vieira
    (...) melhorando minha colocação... a contextualização na implementação dos testes seria assim:

    - Processo > Operação: "Vendas de Produtos" > "Carrinho de compra".
    - Contexto: Xxxxx.Vendas.Produtos

    - Classe: CarrinhoDeCampra
    - Método: ValorTotalDeItems

    - Classe de teste: CarrinhoDeCampraTest ou
    CarrinhoDeCampra.Test
    DadoUmCarrinhoDeCampra.Test
    - Métodos de teste: SeFoiInseridoMaisDeUmItem_CalculaOValorTotal
    QuandoEhInseridoMaisDeUmItem_EntaoCalculaOValorTotal

    Espero der deixado mais clara a minha intenção de sugestão.

    Att.
    Postado em 27/09/13 11:07 em resposta a Marcelo Vieira.