UaiMockServer – Muitas novidades para ajudar ainda mais em seus testes

Olá, tudo bem?

A nova versão do uaiMockServer tem diversas novas funcionalidades que vão revolucionar os frameworks open source que fazem papel de mock HTTP.

A primeira grande novidade é justamente uma tela que permite a edição dos seus requests:

Index

Index

Agora não será mais necessário você editar seus requests através de um tedioso arquivo de configuração, utilize a ferramenta gráfica que fará isso de modo simples e prático. Basta acessar a tela de edição pela URL: http://localhost:1234/uaiGui/index

Outra novidade é justamente poder identificar o que está sendo enviado e recebido no request de um modo prático. Basta ir na aba “Log” e disparar o request:

Request Log

Request Log

Ao detalhar um request com sucesso você poderá ver:

Success Request

Success Request

Ao detalhar um requets com erro você verá como:

Error Detail 01

Error Detail 01

Um detalhe interessante é que será possível ver o Log do Servidor, esse log ajudará analisar o que aconteceu de errado no request:

Error Detail 02

Error Detail 02

E por último, mas não menos importante, agora é possível utilizar Runner em seus testes com JUnit. Veja o exemplo abaixo:

UaiMockServer JUnit Runner

UaiMockServer JUnit Runner

Desse modo você não precisa mais fazer o controle manual do seu servidor. Você também pode especificar qual o arquivo de configuração a ser utilizado:

UaiMockServer JUnit Runner Configuration

UaiMockServer JUnit Runner Configuration

E para você que usa o Spring, você também pode utilizar o Runner especializado para o Spring:

UaiMockServer JUnit SpringRunner Configuration

UaiMockServer JUnit SpringRunner Configuration

Uma última alteração que foi necessário é fazer a troca do tipo do arquivo de configuração, infelizmente não é mais possível usar o arquivo do tipo HCON como na primeira versão. Agora o arquivo deve ser no formato JSON. Peço desculpas ao incômodo que isso possa causar, mas foi uma mudança para melhor.

O arquivo de configuração está como abaixo:

New Configuration File as JSON

New Configuration File as JSON

Uma vantagem em ter o arquivo de configuração em formato JSON é justamente de qualquer editor de texto poder formatar o código.

Site do projeto: http://uaimockserver.com

Código fonte: https://github.com/uaihebert/uaiMockServer

Versão standalone e arquivo de configuração: https://sourceforge.net/projects/uaimockserver/

Import do Maven:

<dependency>
    <groupId>uaihebert.com</groupId>
    <artifactId>uaiMockServer</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

Espero que você goste das novidades.

Qualquer dúvida ou sugestão, poste como comentário abaixo.

o_

uaiMockServer – Crie um servidor Rest de teste com apenas uma linha de comando

Olá, tudo bem?

Sabe aquele momento em que você precisa chamar um serviço REST, mas esse serviço não está pronto ainda?

Imagine que você está desenvolvendo uma nova tela do APP que o serviço REST ainda não está pronto. Nesse caso você precisará ter um código falso em seu projeto, e esse código terá que ser substituído quando o serviço ficar pronto. Não importa se você trabalha com Java, .NET, PHP, Ruby, Python, etc.. Você terá que ter sempre o trabalho de primeiro criar o mock e depois criar a chamada real quando o serviço REST não estiver pronto.

Para testes unitários temos o mesmo problema, é comum termos uma classe com a implementação real e uma classe com um código falso. Na hora do teste é que a classe falsa é utilizada. O ruim dessa abordagem é que o código que executa a chamada nunca é testado.

Como podemos resolver esse problema? E o mais interessante: “existe uma solução que atenda delphi, .NET, PHP, Java, Android, IOS, WindowsPhone, etc?”

Apresento para vocês o mais novo produto que criei: “uaiMockServer

Com o uaiMockServer você poderá criar um servidor de teste utilizando o JAR e um arquivo de configuração. Com o uaiMockServer você poderá disparar os testes usando HTTP, mas com seus dados de testes.

Existem dois modos de utilizar o uaiMockServer: Standalone e com Testes Unitários.

Standalone

O modo standalone é quando você dispara o jar manualmente. Para executar o serviço manualmente basta fazer:

java -jar uaiMockServer-{VERSION}.Standalone.jar

Tudo o que você precisa agora é do arquivo de configuração que estará descrito mais abaixo.

No arquivo exemplo de configuração já vem mapeado um hello world apontando para a porta 1234. Se você estiver usando linux, execute o comando:

curl localhost:1234/uaiMockServer/

E você já verá o JSON retornado.

Testes Unitários

Primeiro passo é adicionar o projeto em seu pom:

<dependency>
   <groupId>uaihebert.com</groupId>
   <artifactId>uaiMockServer</artifactId>
   <version>1.0.1</version>
   <scope>test</scope>
</dependency>

Uma vez que a dependência já está em seu pom você pode criar um teste como o abaixo:

public class YourTest {
    private static UaiMockServer uaiMockServer;

    @BeforeClass
    public static void beforeClass() {
        uaiMockServer = UaiMockServer.start();
    }

    @AfterClass
    public static void afterClass() {
        uaiMockServer.shutdown();
    }

    @Test
    public void aTest() {
        final Customer customer = // invoke the URL
        assertTrue(customer != null);
    }
}

A chamada na URL tem que ser feita com algum framework de sua preferência. Eu coloco abaixo um exemplo feito utilizando RestEasy e o arquivo de configuração (mostrado mais abaixo):

@Test
public void isGetRootReturning200() {
    final String url = "http://localhost:1234/uaiMockServer/";

    Client client = ClientBuilder.newClient();
    Response response = client.target(url).request().get();

    assertEquals(200, response.getStatus());
}

A vantagem disso? Agora você não precisa mais de um código mock em seus testes. Você pode chamar diretamente do JUnit o servidor criado.

Configuração

Para rodar corretamente é necessário um arquivo de configuração. Um exemplo simples seria o arquivo abaixo:

com.uaihebert.uaimockserver {
	port = 1234
	host = localhost
	fileLog = false
	consoleLog = true
	context = /uaiMockServer
	defaultContentTypeResponse = "text/html;charset=UTF-8"
	routes = [
	    {
			request {
				path = "/"
				method = "GET"
			}
			response {
				contentType = "application/json;charset=UTF-8"
				statusCode = 200
				body = """{"mockBody":{"title":"Hello World"}}"""
			}
	    }
    ]
}

O arquivo tem que ter a extensão .config e não está no formato JSON, mas sim é um superset do JSON – HCON – utilizado para configurações (clique aqui para mais detalhes).

Com esse arquivo você pode configurar a porta a ser chamada, o host, header, queryparam e diversas outras funções que estão descritas na documentação do uaiMockServer.

Note que foi criado um request e response desse modo você pode simular toda chamada que você quiser.

Caso você rode a versão Standalone, esse arquivo deve ficar na mesma pasta que o jar. Você também pode passar o caminho completo assim:

java -jar uaiMockServer-{VERSION}.Standalone.jar CAMINHO_COMPLETO_DO_ARQUIVO

Caso você vá rodar o serviço em seus testes unitários (JUnit por exemplo), você deve colocar o arquivo na pasta “src/test/resources” do maven. Você também poderia passar o caminho completo do arquivo como:

uaiMockServer = UaiMockServer.start(CAMINHO_COMPLETO_DO_ARQUIVO);

É grátis?

Sim. Use a vontade.

O código fonte é aberto? Sim: https://github.com/uaihebert/uaiMockServer

A documentação está onde? http://uaimockserver.com

E para baixar o .config e o JAR Standalone? http://sourceforge.net/projects/uaimockserver/files/

Tem teste? Sim, Temos bastantes testes unitários e 100% de cobertura.

Performance desse trem é bom?

No próprio GIT tem um teste que dispara 300 requests e tem todas as resposta em menos de 2 segundos.

Agradecimentos Especiais

Cobrindo seus testes com Cobertura, JUnit, HSQLDB, JPA

Olá tudo bem?

Vamos falar hoje sobre uma ferramenta muito importante chamada Cobertura. Esse framework tem a mesma função de cobertura de testes que o framework Emma, já mostrado aqui.

A diferença é que a tela inicial do framework Cobertura nos mostra os dados de um modo mais gráfico.

Caso você queira ver os outros posts sobre esse assunto,basta clicar nos links a seguir: Cobertura de testes com JUnit Ant e Emma, JUnit com HSQLDB, JPA e Hibernate, Primeiros passos.

Vou utilizar exatamente o código do post JUnit com HSQLDB, JPA e Hibernate. Caso você queira montar o ambiente corretamente, basta fazer o passo a passo que se encontra lá (no fim do post você irá encontrar o código fonte para download).
Eu não sou um usuário habilidoso do ant, você poderá ver algum código e pensar: “ele poderia ter usado o comando xyk”. Fique a vontade para sugerir. ;)

Vamos fazer o download da biblioteca do framework CoberturaDownload1.9.4.1Faça o download e coloque todos os arquivos jars (/cobertura.jar, /lib/* que tem os arquivos asm, jakarta, log4j) dentro na pasta lib do nosso projeto.

Na raiz do seu projeto crie um arquivo chamado “build.xml”com o seguinte código (tem que estar exatamente na raiz do projeto para funcionar):

<project name="Cobertura Coverage" basedir=".">

    <!--  Project Source  Code -->
    <property name="src.dir" value="src" />
    <property name="build.dir" value="bin" />
    <property name="teste.dir" value="src/test" />
    <property name="lib.dir" value="lib" />
    <property name="report.dir" value="cobertura" />

    <!-- Project classpath -->
    <path id="project.classpath">
        <pathelement location="${bin.dir}" />
        <fileset dir="${lib.dir}">
            <include name="*.jar" />
        </fileset>
    </path>

    <!-- Tested Class -->
    <property name="DogFacadeTest" value="test.com.facade.DogFacadeTest" />

</project>

No código acima, estamos apenas declarando os caminhos para o código fonte e as bibliotecas.

Agora vamos criar uma tarefa que irá apagar arquivos criados pelo framework Cobertura e pela compilação do nosso projeto.

<!-- Clears the paths -->
<target name="01-CleannUp" description="Remove all generated files.">
    <delete dir="${build.dir}" />
    <delete file="cobertura.ser" />
    <delete dir="${report.dir}" />

    <mkdir dir="${build.dir}" />
    <mkdir dir="${report.dir}" />
</target>

E para compilar seu código Java, adicione o código abaixo e depois execute para ter a certeza de que está compilando:

<!-- Compiles the Java code -->
<target name="02-Compile" depends="01-CleannUp" description="invoke compiler">
    <javac debug="true" debuglevel="vars,lines,source" srcdir="${src.dir}" destdir="${build.dir}">
        <classpath refid="project.classpath" />
    </javac>
    <copy file="${src.dir}/META-INF/persistence.xml" todir="${build.dir}/META-INF" />
</target>

Vamos configurar o framework Cobertura para que ele possa instrumentar as classes de testes e já preparar o ambiente:

<!-- Cobertura configs -->
<property name="cobertura.instrumented-classes.dir" value="${report.dir}/instrumented-classes" />
<property name="cobertura.data.file" value="cobertura.ser" />
<path id="cobertura.classpath">
    <fileset dir="${lib.dir}" includes="/*.jar" />
</path>

<!-- Points to the cobertura jar -->
<taskdef classpath="${lib.dir}/cobertura.jar" resource="tasks.properties" classpathref="cobertura.classpath" />

<!-- Instruments the classes -->
<target name="03-Instrument" depends="02-Compile">
    <delete quiet="false" failonerror="false">
        <fileset dir="${cobertura.instrumented-classes.dir}" />
    </delete>
    <delete file="${cobertura.data.file}" />
    <cobertura-instrument todir="${cobertura.instrumented-classes.dir}">
        <fileset dir="${build.dir}">
            <include name="**/*.class" />
            <exclude name="**/*Test.class" />
        </fileset>
    </cobertura-instrument>
    <copy todir="${cobertura.instrumented-classes.dir}">
        <fileset dir="${src.dir}" casesensitive="yes">
            <patternset id="resources.ps" />
        </fileset>
    </copy>
</target>

Adicione o código abaixo e vamos executar o JUnit pelo “ant.xml”:

<!-- Set up the instrumented classes path -->
<path id="cover-test.classpath">
    <fileset dir="${lib.dir}" includes="**/*.jar" />
    <pathelement location="${cobertura.instrumented-classes.dir}" />
    <pathelement location="${build.dir}" />
</path>

<!-- Run the JUnit test -->
<target name="04-RunTest" depends="03-Instrument" >
    <junit printsummary="yes" haltonerror="no" haltonfailure="no"  fork="yes">
        <batchtest>
            <fileset dir="${build.dir}" includes="**/*Test.class" />
        </batchtest>
        <classpath refid="cover-test.classpath" />
    </junit>
    <delete file="transaction.log" />
</target>

E por último, vamos executar gerar nosso relatório. Adicione o código abaixo ao “build.xml” e execute a task.

<!-- Creates the Cobertura report -->
<target name="00-CreateReport" depends="04-RunTest">
    <cobertura-report srcdir="${cobertura.data.file}" destdir="${report.dir}">
        <fileset dir="${src.dir}">
            <include name="**/*.java" />
        </fileset>
    </cobertura-report>
    <delete dir="${report.dir}/instrumented-classes" />
    <delete file="cobertura.ser"  />
</target>

Atualize seu projeto no Eclipse (F5 no projeto) e você verá que os arquivos do relatório foram criados com sucesso. Abra o arquivo “index.html” que estará dentro da pasta cobertura.




O framework Cobertura inclusive mostra quantas vezes você tem que testar um método. Como desafio, escreva o método equals da classe Dog,gere o relatório só para você conferir que não está sendo coberto. E crie seus testes e olhe depois a cobertura do seu método como ficou.

Você poderá fazer o download do código do post de hoje.

Qualquer dúvida/comentário basta postar.

Até a próxima! o_

TDD Cobertura de testes com JUnit Ant e Emma

Olá pessoal, bom dia.

Quando escrevemos testes temos sempre a preocupação de saber se estamos testando toda nossa classe. Imagine só, testar 4 métodos e esquecer de simular um caso de teste que caia em uma Exception do Try/Catch?

Para solucionar esse problema existem ferramentas para cobrir seu teste, que irão informar por onde seu teste passou ou deixou de passar.

Vou falar sobre duas ferramentas para cobertura do seu teste Emma (no post de hoje) e Cobertura (no próximo post sobre TDD).

Vou usar exatamente o código deste post (TDD com HSQLDB, JPA e Hibernate). Se você quiser montar um ambiente, siga o que for descrito no post anterior e tudo irá funcionar 100%. Outro post sobre o assunto é: TDD – Primeiros passos.

Hoje iremos utilizar o framework Emma com Ant. Não sou um bom conhecedor ainda do Ant, então os códigos que “garimpei” pela internet talvez tenha alguma redundância ou coisa assim. Um dia irei melhorá-lo.

Vamos começar com os downloads:

O JUnit é utilizado apenas pelo o framework do Emma possa executar os testes.

Copie as bibliotecas do Emma e do JUnit para a pasta lib; não será necessário adicioná-los ao “Build Path” do projeto.

Crie um arquivo chamado “build.xml” na raiz do seu projeto (
o arquivo tem que ficar exatamente na raiz do projeto, ou então o script irá falhar)
.

Altera altere o arquivo para ficar com o seguinte código:

<project name="Emma Reports" basedir=".">

    <!--  Project Source  Code -->
    <property name="src.dir" value="src" />
    <property name="bin.dir" value="bin" />
    <property name="teste.dir" value="src/test" />
    <property name="lib.dir" value="lib" />

    <!-- Emma source code -->
    <property name="emma.bin.dir" value="emma/bin" />
    <property name="emma.metadate.dir" value="emma/metadate" />
    <property name="emma.report.dir" value="emma/report" />

    <!-- Tested Class -->
    <property name="DogFacadeTest" value="test.com.facade.DogFacadeTest"/>

    <!-- Project classpath -->
    <path id="project.classpath">
        <pathelement location="${bin.dir}" />
        <fileset dir="${lib.dir}">
            <include name="*.jar" />
        </fileset>
    </path>

    <!-- Emma task definitions that you will find inside the jar -->
    <taskdef resource="emma_ant.properties">
        <classpath refid="project.classpath" />
    </taskdef>

    <!-- JUnit task definition -->
    <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask" />

</project>

No arquivo build.xml estamos definindo as variáveis do script, os caminhos dos arquivos e o JUnit a ser executado.

Agora vá ao menu Window > Show View > Other. Digite Ante aperte Ok:


Arraste o arquivo para o dentro do da view do Ant. Duplo click no arquivo para executá-lo. A seguinte mensagem irá aparecer:

Caso a mensagem “Could not load definitions from resource emma_ant.properties. It could not be found.” É por que o caminho da sua lib está errado. Verifique novamente se o seu arquivo“build.xml” está na raiz do projeto. Não prossiga sem resolver esse problema de path.

Vamos alterar nosso “build.xml” e fazer com que ele a partir de agora compile nosso código java. Ele tem dois passos (ações chamadas de “target”).

    <!-- Clean UP Your Code -->
    <target name="01-CleanUp">
        <delete dir="${bin.dir}" />
        <mkdir dir="${bin.dir}" />
    </target>

    <!-- Compile Your Code -->
    <target name="02-CompileSourceCode" depends="01-CleanUp">
        <javac debug="on" srcdir="${src.dir}" destdir="${bin.dir}">
            <classpath refid="project.classpath" />
        </javac>
        <copy file="${src.dir}/META-INF/persistence.xml" todir="${bin.dir}/META-INF" />
    </target>

Perceba que temos as ações “01-CleanUp” e “02-CompileSourceCode”onde a ação de compilar “depends” da ação de limpar o código, com isso, toda vez que você quiser compilar o projeto o Ant irá executar a ação de limpar automaticamente.

Vamos gerar agora a task com uma palavra que você irá ouvir muito, Instrumentação. Falando vagamente, o Emma ele é bytecode instrumentado,ou seja, ele não necessita de adaptações ou alterações na JVM para mensurar o seu código. Ele analisa o seu bytecode e pronto.

Vamos alterar o build.xml e adicionar a task:

    <!-- Generate the Emma  -->
    <target name="03-Instrumentation" depends="02-CompileSourceCode">
        <emma>
            <instr instrpath="${bin.dir}" destdir="${emma.bin.dir}" metadatafile="${emma.metadate.dir}/metadate.emma" merge="false" mode="fullcopy" />
        </emma>
    </target>

Vamos criar agora, a chave que irá compilar e executar o teste JUnit:

    <!-- Runs JUnit Tests -->
    <target name="04-RunTests" depends="03-Instrumentation">
        <junit haltonfailure="false" haltonerror="false" fork="true">
            <classpath>
                <pathelement location="${emma.bin.dir}/classes" />
                <pathelement location="${emma.bin.dir}/lib" />
                <path refid="project.classpath" />
            </classpath>
            <formatter type="plain" usefile="false" />
            <test name="${DogFacadeTest}" />
            <jvmarg value="-Demma.coverage.out.file=${emma.metadado.dir}/cobertura.emma" />
            <jvmarg value="-Demma.coverage.out.merge=false" />
        </junit>
    </target>

Execute o teste e veja que o nosso teste não retornou erro:

Vamos criar agora o nosso gerador de relatório:

    <!-- Creates the report -->
    <target name="00-GenerateReport" depends="04-RunTests">
        <delete dir="${emma.report.dir}" />
        <emma enabled="true">
            <report sourcepath="${src.dir}" sort="+block,+name,+method,+class" metrics="method:70,block:80,line:80,class:100">
                <fileset dir="${emma.metadate.dir}">
                    <include name="*.emma" />
                </fileset>
                <html outfile="${emma.report.dir}/report.html" depth="method" columns="name,class,method,block,line" />
            </report>
        </emma>
    </target>

Execute a tarefa de Gerar relatório e abra o arquivo que irá aparecer em “
/emma/report/report.html
”.


E por ultimo vamos apagar os arquivos que foram gerados para que o relatório fosse extraído.

Altere a task para gerar relatório e vamos criar uma task que irá ser chamada automaticamente pelo Ant após gerar um relatório:

    <!-- Creates the report -->
    <target name="00-GenerateReport" depends="04-RunTests">
        <delete dir="${emma.report.dir}" />
        <emma enabled="true">
            <report sourcepath="${src.dir}" sort="+block,+name,+method,+class" metrics="method:70,block:80,line:80,class:100">
                <fileset dir="${emma.metadate.dir}">
                    <include name="*.emma" />
                </fileset>
                <html outfile="${emma.report.dir}/report.html" depth="method" columns="name,class,method,block,line" />
            </report>
        </emma>

        <antcall target="05-DeleteOldReportData" />
    </target>

    <!-- Delete Old Report Data -->
    <target name="05-DeleteOldReportData">
        <delete dir="${emma.bin.dir}" />
        <delete dir="${emma.metadate.dir}" />
    </target>

Click aqui para fazer o download do tutorial de hoje.
Espero que esse post possa te ajudar.

Qualquer dúvida ou comentário, basta colocar.

Inté+! o_

OBS.: Fonte de pesquisa:

JUnit com HSQLDB, JPA e Hibernate

Olá, bom dia.

Vamos falar hoje em como integrar seus testes unitários utilizando um banco de dados? Uma das melhores soluções do mercado atualmente é utilizarum banco de dados em memória.

O banco de dados HSQLDB faz todo esse trabalho de, criar aestrutura de tabelas, relacionamento entre as chaves e permitir que o JPAconsiga trabalhar sem problemas.

Nesse tutorial vamos ver como criar teste unitário (TDD) comJPA e HSQLDB.

Para ver o outro post sobre TDD você pode clicar aqui: TDD – Primeiros passos.

Você irá precisar fazer o download do JAR do HSQLDB aqui (hsqldb.org/Versão2.25 – Última versão).

Vou utilizar o Hibernate como provider do JPA. Nessetutorial (Tutorial Hibernate 3 com JPA 2) você irá encontrar os links necessários para download.

Crie um projeto Java em File > New Project > JavaProject.

Crie uma pasta lib e dentro dela coloque todas asbibliotecas necessárias dentro dessa pasta. Os arquivos são as bibliotecas do HSQLB e do Hibernate.

Vou resumir daqui para frente, mas no tutorial (Tutorial Hibernate 3 com JPA 2) mostracomo colocar seu projeto para executar com sucesso o Hibernate.

Clique com o botão direito do mouse sobre o Projeto >Properties. Vá a Java Build Path > aba Libraries > Add Jars.Selecione as bibliotecas que lá estão e aperte Ok.

Crie uma pasta chamada “src/META-INF” e dentro dela coloqueo seu persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="HsqldbWithTDD" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:." />
            <property name="javax.persistence.jdbc.user" value="sa" />
            <property name="javax.persistence.jdbc.password" value="" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.connection.shutdown" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        </properties>
    </persistence-unit>
</persistence>

Vamos criar a classe Dog que será persistida.

package com.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "dog")
@NamedQuery(name="listALL", query="select d from Dog d")
public class Dog {

    public static final String LIST_ALL = "listALL";

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    private double weight;

    // Getters and Setters
}

Vamos criar agora a classe DAO que irá ter um CRUD básico da classe Dog (Na classe Dog você irá a anotação @NamedQuery, ainda não vimos aqui no blog mas basicamente é um SQL que irá realizar a consulta):

package com.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import com.model.Dog;

public class DogDAO {

    private EntityManagerFactory emf;
    private EntityManager em;

    public void startConnection(){
        emf = Persistence.createEntityManagerFactory("HsqldbWithTDD");
        em = emf.createEntityManager();
        em.getTransaction().begin();
    }

    public void closeConnection(){
        em.getTransaction().commit();
        emf.close();
    }

    public void save(Dog dog){
        em.persist(dog);
    }

    public void edit(Dog dog){
        em.merge(dog);
    }

    public Dog find(int dogId){
        return em.find(Dog.class, dogId);
    }

    public void remove(Dog dog){
        em.remove(dog);
    }

    public List listALL(){
        return em.createNamedQuery(Dog.LIST_ALL, Dog.class).getResultList();
    }
}

Vamos testar se nossa informação está sendo persistida? Vamos criar uma classe Main e executar um teste, o resultado da classe Main deve ser como a figura abaixo:

package com;

import com.dao.DogDAO;
import com.model.Dog;

public class Main {

    public static void main(String[] args) {
        DogDAO dogDAO = new DogDAO();

        dogDAO.startConnection();

        try {
            Dog dog = new Dog();
            dog.setName("Beethoven");
            dog.setWeight(45);

            dogDAO.save(dog);

            // It was the first saved dog, so its id is 1
            Dog persistedDog = dogDAO.find(1);

            System.out.println("Name: " + persistedDog.getName());
            System.out.println("Weight: " + persistedDog.getWeight());
        } catch (Exception e) {
            System.out.println("Ops, something happen: " + e.getMessage());
            e.printStackTrace();
        }finally{
            dogDAO.closeConnection();
        }
    }
}


Agora, vamos utilizar a metodologia de TDD para criar um método/classe? Vamos simular que, precisamos de um método que calcule a média de peso de todos os cachorros cadastrados no sistema.

Vou criar a classe DogFacade que irá fazer esse trabalho, einclusive será ela quem irá trabalhar com o DAO.

Vamos configurar a biblioteca do JUnit em nosso sistema, namesma tela em que adicionamos as bibliotecas do Hibernate e do HSQLDB. Cliqueem Add Library.

Selecione JUnit 4 e pronto.

Seguindo boas práticas do TDD, vamos criar nossa classe deteste sem ter a classe DogFacade criada.

package test.com.facade;

import static junit.framework.Assert.assertEquals;

import org.junit.Test;

import com.model.Dog;

public class DogFacadeTest {

    @Test
    public void isWeightOfAllDogsCorret(){
        DogFacade dogFacade = new DogFacade();
        dogFacade.startConnection();

        createData(dogFacade);
        assertEquals(30, dogFacade.getAverageDogsWeight());

        dogFacade.closeConnection();
    }

    private void createData(){
        Dog dogA = new Dog();
        dogA.setName("Big Dog");
        dogA.setWeight(45);

        Dog dogB = new Dog();
        dogB.setName("Medium Dog");
        dogB.setWeight(30);

        Dog dogC = new Dog();
        dogC.setName("Small Dog");
        dogC.setWeight(15);
    }
}

Ao criar essa classe vários erros serão exibidos, masseguindo o princípio do TDD, “Vermelho, Verde, Refatorar”!  Para mais detalhes veja aqui (TDD – Primeiros passos).

Como nosso exemplo é simples, estou deixando o Facadegerenciando a conexão. Em uma aplicação web uma boa saída seria utilizar ainjeção de recursos, para continuar utilizando essa abordagem você pode adotaro que for melhor para você (algumas sugestões minhas, mas você poderá achar outraspela internet):

  • Passar o EntityManager por construtores. Sua classe de teste criaria o EntityManager através do EntityManagerFactory e o enviaria através de um construtor sobrecarregado. Ficaria assim: new DogFacade(entityManager); e dentro do Facade você iria fazer new DogDao(entityManager).
  • Criar o DAO na classe de teste com a conexão ativa e passar o DAO através de construtores sobrecarregados nos Facades.

Será necessário adotar alguma estratégia ou então vai choverNullPointer em seus testes. A parte ruim dessa estratégia é que sua classeFacade vai ficar conhecendo o EntityManager, ou ter uma dependência em umconstrutor de DAO. Mas esses construtores serão utilizados apenas em testes,não irão/devem interferir na aplicação em tempo real.

Vamos ver como ficou nossa classe DogFacade:

package com.facade;

import java.util.List;

import com.dao.DogDAO;
import com.model.Dog;

public class DogFacade {

    private DogDAO dogDAO;

    public DogFacade() {
        dogDAO = new DogDAO();
    }

    public void startConnection() {
        dogDAO.startConnection();
    }

    public double getAverageDogsWeight() {
        double totalWeight = 0;

        List dogs = dogDAO.listALL();

        for(Dog dog : dogs){
            totalWeight += dog.getWeight();
        }

        return totalWeight / dogs.size();
    }

    public void save(Dog dog){
        dogDAO.save(dog);
    }

    public void closeConnection() {
        dogDAO.closeConnection();
    }
}

Vamos executar nosso teste novamente?


Considerações Finais:

  • Eu prefiro essa abordagem a realizar Mocks. Um objeto “mocado” não irá se comportar como você não espera, esse objeto irá apenas se comportar do modo que ele foi programado. Em nosso caso o DAO não teve nenhum método “mocado”. Utilizamos o Facade de modo natural e não alteramos nenhum dos seus métodos.
  • Vejo o mock sendo realmente útil em casos onde são necessárias conexões com outras aplicações ou em aplicações de código legado onde o grau de complexidade é alta e utilizar essa abordagem seria muito custosa.
  • Com esse tipo de abordagem poderemos inclusive criar testes para as classes de view: JSF, Struts, Seam, etc. Próximo post que vou escrever sobre esse assunto! ;)

Espero que esse post possa te ajudar.

Qualquer dúvida ou colocação, basta postar.

Até +! o_

TDD – Primeiros passos

O que é TDD? Por onde começar um Teste? Como se faz um Teste?

TDD é uma metodologia de validação das classes/métodos/atributos que serão criados. Por exemplo, foi solicitado criar um método que busque os dados de uma casa. Com o TDD, é possível validar todas as situações que o desenvolvedor possa imaginar, como: casa sem número, valor retornado null, dono se mudou, etc.

Por onde começar? Vamos configurar o JUnit para ficar mais clara nossa visão? Desculpe se você já sabe fazer isso, é coisa rápida (temos que ajudar quem está começando!).
Irei usar o Eclipse como IDE, mas na verdade o TDD pode (e deve) ser aplicado em qualquer IDE. Caso você use outra ferramenta de teste que não seja o JUnit, o conceito que será passado aqui é aplicável a qualquer ferramenta de teste.

OBS.: Esses pequenos passos de como criar classes/pacotes ou abrir uma view do Eclipse você pode achar em outro post aqui no blog: Criando um WebServer

Após criar um novo “Java Project” que chamarei de TDD, utilizando a View “Package Explorer”, adicione a biblioteca do JUnit:
Configurando 01
Configurando 02
Configurando 03

Vamos trabalhar em cima do seguinte caso de uso: Seu sistema terá uma classe User que manterá as informações de cada pessoa que faz o login no sistema. E como requisito, essa classe terá um método para bloquear o acesso de um usuário ao sistema.
Vamos criar um pacote chamado “test.com” e uma classe chamada TestUser dentro deste pacote.

package test.com;

public class TestUser {
}

A ideologia base do TDD é começar o teste pelo resultado esperado. (HEIN?!) No mercado o costume sempre foi começar a codificar pelo começo, mas no TDD nós começamos pelo fim. Por quê? Fazendo assim temos uma idéia para onde vamos, o que vamos precisar para chegar até lá, evitamos criação de parâmetros desnecessários, os métodos ficam mais objetivos e assim vai.

Ao escrever métodos temos que ter em mente a seguinte seqüência: “Vermelho, Verde, Refatorar”. O que seria isso? Quando escrevemos testes utilizando JUnit temos a barra (que em breve veremos) mostrando status vermelho para quando o teste falha, e verde para quando tudo é executado com sucesso.

Para garantir um resultado experado, existem métodos que fazem essa conferência. Vamos utilizar o assertEquals(valor desejado, valor retornado). Em nosso caso de uso, o que queremos? Sempre que o usuário estiver bloqueado o método terá que retornar verdade. Vamos escrever esse código?

package test.com;
import static org.junit.Assert.*;
import org.junit.Test;

public class TestUser {
    @Test
    public void isUserWithDeniedAccess(){
        assertEquals(true, user.accessDenied);
    }
}

Alguns detalhes sobre o código. Note que temos um annotation “@Test” e ao executarmos o framework do JUnit ele irá localizar os métodos que tiverem esse annotation, e irá executar a validação do teste. Estamos utilizando o método assertEquals que é importado do próprio JUnit utilizando o “import static”.

Perceba também que já estou “tentando” acessar um objeto que não existe tanto no método, tão pouco no projeto. Está lembrado de quando falei que começamos do fim? O nosso fim (alvo, meta) é que o usuário no final das contas esteja realmente bloqueado. Mesmo que não exista classe ou seus atributos ainda, iremos normalmente, como passo inicial, utilizá-lo em nosso código. Fazendo assim, já estamos pensando no nome da classe, dos atributos. Mesmo que não compile, estamos no caminho. Pequenos passos… Sempre pequenos passos…
Finalizando nosso teste, nosso código ficará assim:

@Test
public void isUserWithDeniedAccess(){
        User user = new User();
        assertEquals(true, user.accessDenied);
}

Note que foi “instanciada” a classe User mesmo sem ela existir no projeto. Agora temos um projeto em que o teste não é compilável.
Lembram-se dos passos do TDD? Vermelho, Verde e Refatorar? Temos que conseguir uma barra vermelha retirando os erros de compilação. Vamos criar nossa classe User (em um pacote chamado “com”) e adicionar o atributo necessário.

package com;
public class User {
    public boolean accessDenied;
}

Agora basta fazer o import na classe de teste (TestUser):

import com.User;

E já estamos prontos para conseguir nossa barra vermelha. Para rodar o teste pelo JUnit basta clicar com botão direito em cima da nossa classe de teste ir em “Run as > JUnit Test”.
Executando o JUnit
A barra vermelha nos indica que agora estamos prontos para trabalhar o nosso método para que ele possa retornar o valor desejado. Começamos pelo erro para saber que, ao conseguir o verde, nosso teste realmente esta trabalhando como desejamos. Nesse caso estamos a fazer um exemplo bem direto, mas se estivéssemos fazendo um método complexo, começar pelo erro faria com que tivéssemos a certeza de que atingimos nosso objetivo. Com isso, não precisamos executar toda a aplicação para fazer o teste da funcionalidade, basta rodar os testes e pronto, já podemos ver rapidamente o resultado da nossa alteração.

Agora vamos desenvolver nosso código para que nossa barra possa ficar verde? Nessa hora, geralmente, alteramos o método que acabamos de criar para retornar o valor desejado. Como nosso exemplo é simples, basta trabalhar com o valor do atributo para consigamos o valor desejado. O nosso teste é quem tem quem deve estimular a classe nas situações desejadas, por isso não estamos alterando em nada a classe User para que nosso teste execute. TDD trabalha com pequenos passos, caso você já esteja com um bom nível em TDD já seria possível criar os métodos de uma só vez. Por isso estamos acessando diretamente os atributos, mas de acordo com algumas literaturas de TDD é uma boa prática acessar os atributos pois você já estaria validando os mesmos em sua fase de teste, e depois, com a refatoração seriam criados os métodos para proteger os atributos

@Test
public void isUserWithDeniedAccess(){
        User user = new User();
        user.accessDenied = true;
        assertEquals(true, user.accessDenied);
}

E agora basta executar o JUnit o código que teremos a barra verde.

Note que nosso código está feio, e não está aplicando nenhum padrão OO. O que fazer? Esse ato de refatorar sempre fica para o final, então vamos adicionar ao final da nossa lista de tarefas onde iremos refatorar. Assim não iremos deixar nada para trás.

Usando essa abordagem de código temos uma visão melhor do código, de onde poderíamos alterá-lo ou melhorá-lo. E melhor, temos a certeza de que nosso código já está fazendo o que nós queríamos. Mas precisamos aplicar conceitos OO antes de dar a tarefa como concluída. Vamos primeiro criar um método para verificar se o usuário tem seu acesso negado ao invés de acessar o atributo direto.

// TestUser.java
package test.com;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.User;

public class TestUser {
    @Test
    public void isUserReallyBlocked(){
        User user = new User();
        user.accessDenied = true;
        assertEquals(true, user.hasAccesDenied());
    }
}

//User.java
package com;

public class User {
    public boolean accessDenied;

    public boolean hasAccesDenied() {
        return accessDenied;
    }
}

Não alteramos o acesso ao atributo ainda pois temos mais um passo pela frente. Vamos criar um meio para que a classe altere o atributo e proteja o atributo de um acesso direto. Para isso, vamos usar o conceito Diga, não pergunte. Fazendo assim, de um modo eficiente iremos terminar nosso caso de teste e nossa tarefa. Nosso código final seria:

package test.com;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.User;

public class TestUser {
    @Test
    public void isUserReallyBlocked(){
        User user = new User();
        user.denyAcces();
        assertEquals(true, user.hasAccesDenied());
    }
}

package com;

public class User {
    private boolean accessDenied;

    public boolean hasAccesDenied() {
        return accessDenied;
    }

    public void denyAcces() {
        accessDenied = true;
    }
}

Note como o código da classe User ficou claro, objetivo, sem métodos desnecessários. Começando pelo teste nosso foco é maior no comportamento. Basta agora compilar o teste utilizando o JUnit e ver que concluímos tudo com sucesso.

Pessoal, esperem que ajude esse post para os primeiros passos. Em breve irei colocar aqui, boas práticas de TDD para que possamos aprimorar ainda mais o nosso desenvolvimento. O post de hoje foi apenas uma introdução mais a ferramenta em si, no próximo post sobre TDD iremos falar mais sobre conceitos e abordagens do TDD.

Boa noite a todos.