[Resolvido] JUnit no DAO

Ola pessoal.
Estou com o seguinte problema: já tenho meus DAOS e estou criando os testes automatizados. Um deles nao passou conforme a figura abaixo. Alguem saberia solucionar ? Agradeço pela ajuda.

O erro é o seguinte :


//classe DAO de teste (junit 4.5):

package br.com.bb.agendaTelefonicaCompe.dao;

import br.com.bb.agendaTelefonicaCompe.entity.Empresa;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author mud
 */

public class EmpresaDAOTest {

    public static Integer idOfEmpresa = 0;
    
    public EmpresaDAOTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    @Test
    public void testAddEmpresa() throws Exception {
        System.out.println("addEmpresa");
        Empresa empresa = new Empresa();
        empresa.setNome("BIOLAB");
        empresa.setCnpj("000191");
        empresa.setEndereco("RUA BETA 2");
        empresa.setConta("12345");
        empresa.setId_contato(22);
        EmpresaDAO instance = new EmpresaDAO();
        idOfEmpresa = instance.addEmpresa(empresa);
        assertTrue (idOfEmpresa > 0);
    }

    @Test
    public void testGetEmpresa() throws Exception {
        System.out.println("getEmpresa");
        int idEmpresa = idOfEmpresa;
        EmpresaDAO instance = new EmpresaDAO();
        Integer expResult = idOfEmpresa;
        Empresa result = instance.getEmpresa(idEmpresa);
        assertEquals(expResult, result.getId());
    }
    
    @Test
    public void testUpdateEmpresa() throws Exception {
        System.out.println("updateEmpresa");
        EmpresaDAO instance = new EmpresaDAO();
        Empresa empresa = instance.getEmpresa(idOfEmpresa);
        empresa.setNome("BIOLAB SA");
        instance.updateEmpresa(empresa);
        empresa = instance.getEmpresa(idOfEmpresa);
        assertEquals(empresa.getNome(),"BIOLAB SA");
    }
        
    @Test
    public void testRemoveEmpresa() throws Exception {
        System.out.println("removeEmpresa");
        EmpresaDAO instance = new EmpresaDAO();
        instance.removeEmpresa(idOfEmpresa);        
    } 
}

/*esta é a classe DAO:
#Código
/**
 * EmpresaDAO.java
 *
 * $Id$
 *
 */
package br.com.bb.agendaTelefonicaCompe.dao;

/**
 *
 * @author mud
 */

import br.com.bb.agendaTelefonicaCompe.entity.Empresa;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
/**
 *
 * @author mud
 */
public class EmpresaDAO extends GenericDAO {

    private static final long serialVersionUID = 1L;
    
public EmpresaDAO() {
    }

    public int addEmpresa(Empresa empresa) throws SQLException {
        empresa.setId(getNextId("EMPRESA"));
        String query = "INSERT INTO APP.EMPRESA(ID,NOME,CNPJ,ENDERECO,CONTA,ID_CONTATO) values (?,?,?,?,?,?)";
        executeCommand(query, empresa.getId(), empresa.getNome(), empresa.getCnpj(), empresa.getEndereco(),empresa.getConta(),empresa.getId_contato());
        return empresa.getId();
    }

    public void removeEmpresa(int idEmpresa) throws SQLException {
        executeCommand("DELETE FROM APP.EMPRESA WHERE ID = ?", idEmpresa);
    }

    public void updateEmpresa(Empresa empresa) throws SQLException {
        String query = "UPDATE APP.EMPRESA SET NOME=?,CNPJ=?,ENDERECO=?,CONTA=?,ID_CONTATO=? WHERE ID = ?";
        executeCommand(query, empresa.getNome(), empresa.getCnpj(), empresa.getEndereco(),empresa.getConta(),empresa.getId_contato(), empresa.getId());
    }

    public Empresa getEmpresa (int idEmpresa) throws SQLException {
        ResultSet rs = executeQuery("SELECT * FROM APP.EMPRESA WHERE ID = ?", idEmpresa);
        Empresa empresa = null;
        if (rs.next()) {
            empresa = populateEmpresaInfo(rs);
        }
        rs.close();
        return empresa;
    }

    public List getAllEmpresas() throws SQLException {
        ResultSet rs = executeQuery("SELECT * FROM APP.EMPRESA");
        List toReturn = new LinkedList();
        while (rs.next()) {
            toReturn.add(populateEmpresaInfo(rs));
        }
        rs.close();
        return toReturn;
    }

    public static Empresa populateEmpresaInfo(ResultSet rs) throws SQLException {
        Empresa toReturn = new Empresa();
        toReturn.setId(rs.getInt("ID"));
        toReturn.setNome(rs.getString("NOME"));
        toReturn.setCnpj(rs.getString("CNPJ"));
        toReturn.setEndereco(rs.getString("ENDERECO"));
        toReturn.setConta(rs.getString("CONTA"));
        //toReturn.setContato(ContatoDAO.getContato(rs.getInt("ID_CONTATO")));
        return toReturn;
    }
}

/*esta é a classe GenericDAO:

#Código
/**
 * GenericDAO.java
 *
 * $Id$
 *
 */
package br.com.bb.agendaTelefonicaCompe.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author mud
 */
public abstract class GenericDAO {
    
    private static final long serialVersionU = 1L;

    public Connection getConnection(){
        try {
            Class.forName("org.apache.derby.jdbc.ClientDriver");
            Connection cx = DriverManager.getConnection("jdbc:derby://localhost:1527/csaDB", "admin", "32716397");
            return cx;
        } catch (Exception ex) {
            Logger.getLogger(GenericDAO.class.getName()).log(Level.SEVERE, null, ex);
            return null;        
        }
    }

    public Statement getStatement() throws SQLException {
        return getConnection().createStatement();
    }
        
    public PreparedStatement getStatement(String st) throws SQLException {
        return getConnection().prepareStatement(st);
    }

public ResultSet executeQuery(String query, Object... params) throws SQLException {
    
    PreparedStatement ps = getStatement(query);
    for (int i = 0; i
        ps.setObject(i+1, params[i]);
      }
    return ps.executeQuery();
  }

public int executeCommand (String query, Object... params) throws SQLException {
    
    PreparedStatement ps = getStatement(query);
    for (int i = 0; i
        try {
        ps.setObject(i+1, params[i]);
      } catch (Exception e) {
          System.out.println("Error to try "+i+" with value "+params[i]);
      }
    }
    int result = ps.executeUpdate();
    ps.close();
    return result;
    }

public Integer getNextId (String tableName) throws SQLException {
    ResultSet rs = executeQuery("select MAX(ID) from APP." + tableName);
    rs.next();
    Object result = rs.getObject(1);
    if (result == null) {
        rs.close();
        return 1;
    } else {
        return ((Integer)result)+1;
    }
  }
}

Entao, eu até consegui fazer o JUnit test do ‘update’ funcionar (que é o ñ estava passando), mas no caso tive que fazer um ‘setAtributo’ para todos os atributos, excluindo o setId (que é auto incremental e é a PK do BD). Isso indica que, futuramente, quando eu der um update na aplicação já pronta, não poderei fazer update em apenas um campo. Por ex, se eu quiser alterar apenas o nome de um registro, teria que fazer update nos demais atributos do registro (ou seja, alem do update nome, teria q fazer update tambem para todos os outros atributos do registro correspondente -> cnpj, endereco e conta. Mas gostariamos de alterar apenas o nome.

Desde já agradeço pela atenção.

humm…

bixo vc percebeu que o seu teste PRECISA ir no banco de dados. se vc tem qualquer problema entre a sua classe e o banco vai interferir no teste.

IMHO este tipo de teste é valido, pois mostra que REALMENTE vc vai no banco, porém vc precisa deixar isto bem claro. E se vc vai ao banco a cada teste vc precisa LIMPAR e fazer um SETUP o banco do contrario vc pode testar algo que foi alterado por um teste anterior. Para isso vc faz setUp e tearDown.

em segundo lugar vc podetar testar o código. Vc esta JDBC, certo? o JDBC ja foi bem testado, vc pode confiar que as chamadas aos métodos realmente fazem o que vc espera. Dessa forma vc poderia testar se o seu DAO esta passando as queries e parametros adequados ao JDBC. Como fazer isso? vc cria um objeto mock que representa a sua conexão com o banco de dados e programa este mock (existem varios frameworks para isso, o jMock é um deles) para esperar uma série de invocações de metodos.

O grande valor disso é que vc não precisa de um banco de dados. Vc testa se vc esta chamando os metodos certos.

Combinando os dois vc testa o codigo e a integração do codigo com o JDBC.

Agora eu faço um parentesis: o teste de codigo é dificil a medida que o seu design é dificil. Por exemplo, para mockar a conexão com o banco vc precisa injetar a conexão “mockada”. Hum… se o seu codigo é muito amarrado não vai ser facil, ai vc refatora para propiciar um codigo mais limpo, etc.

No caso do seu erro eu tentaria executar o codigo na mão e ver o que falta.

[quote=peczenyj]humm…

bixo vc percebeu que o seu teste PRECISA ir no banco de dados. se vc tem qualquer problema entre a sua classe e o banco vai interferir no teste.

IMHO este tipo de teste é valido, pois mostra que REALMENTE vc vai no banco, porém vc precisa deixar isto bem claro. E se vc vai ao banco a cada teste vc precisa LIMPAR e fazer um SETUP o banco do contrario vc pode testar algo que foi alterado por um teste anterior. Para isso vc faz setUp e tearDown.

em segundo lugar vc podetar testar o código. Vc esta JDBC, certo? o JDBC ja foi bem testado, vc pode confiar que as chamadas aos métodos realmente fazem o que vc espera. Dessa forma vc poderia testar se o seu DAO esta passando as queries e parametros adequados ao JDBC. Como fazer isso? vc cria um objeto mock que representa a sua conexão com o banco de dados e programa este mock (existem varios frameworks para isso, o jMock é um deles) para esperar uma série de invocações de metodos.

O grande valor disso é que vc não precisa de um banco de dados. Vc testa se vc esta chamando os metodos certos.

Combinando os dois vc testa o codigo e a integração do codigo com o JDBC.

Agora eu faço um parentesis: o teste de codigo é dificil a medida que o seu design é dificil. Por exemplo, para mockar a conexão com o banco vc precisa injetar a conexão “mockada”. Hum… se o seu codigo é muito amarrado não vai ser facil, ai vc refatora para propiciar um codigo mais limpo, etc.

No caso do seu erro eu tentaria executar o codigo na mão e ver o que falta.
[/quote]

excelente resposta, e alem do mais testes de unidades devem ser bem especifico, vc quer testar apenas uma parte da aplicacao ou como dizem uma parte do negocio, “pouco importa” se a conexao está ativa ou nao, o teste ele vai esperar um determinado resultado e vc tem que reproduzir ele garantido que sua app está funcionando. e um detalhe importante, ao modificar algo é comum quebrar em outro lugar, ai que entra o ponto da refatoracao como citado pelo colega acima.

Para objetos mocks eu tenho usado o mockito do google, e tenho gostado dele veja:
http://code.google.com/p/mockito/