【问题标题】:Unit test DAO classes with JUnit using a Connection Pool使用连接池使用 JUnit 对 DAO 类进行单元测试
【发布时间】:2021-02-27 09:12:00
【问题描述】:

大家好,我是新来的,我需要您的帮助来使用 junit 对带有连接池的 DAO 类进行单元测试。 这是 ConPool:

public class ConPool {

private static DataSource datasource;

/**
 * {@return} Connection
 * {@throws} SQLException
 *     Ritorna la connessione al db.
 */

public static Connection getConnection() throws SQLException {
if (datasource == null) {
  PoolProperties p = new PoolProperties();
  p.setUrl("jdbc:mysql://localhost:3306/GameLand?serverTimezone="
          + TimeZone.getDefault().getID());
  p.setDriverClassName("com.mysql.cj.jdbc.Driver");
  p.setUsername("root");
  p.setPassword("basedidati");
  p.setMaxActive(100);
  p.setInitialSize(10);
  p.setMinIdle(10);
  p.setRemoveAbandonedTimeout(60);
  p.setRemoveAbandoned(true);
  datasource = new DataSource();
  datasource.setPoolProperties(p);
}
  return datasource.getConnection();
 }
}

这是我要测试的 DAO 类:

public class OrdineDAO {
/**
 * {@return} ArrayList of Ordine.
 */

public synchronized ArrayList<Ordine> doRetrieveAll() {

String query = "SELECT * FROM ordine";
ArrayList<Ordine> result = new ArrayList<Ordine>();

try (Connection conn = ConPool.getConnection()) {

  PreparedStatement ps = conn.prepareStatement(query);
  ResultSet rs = ps.executeQuery();
  while (rs.next()) {

    Ordine ord = new Ordine();
    ord.setConsegnato(rs.getBoolean("consegnato"));
    ord.setDataOra(rs.getString("dataOra"));
    ord.setIdOrdine(rs.getInt("idOrdine"));
    ord.setIdProdotto(rs.getInt("idProdotto"));
    ord.setPrezzoFis(rs.getDouble("prezzoFis"));
    ord.setPrezzoDig(rs.getDouble("prezzoDig"));
    ord.setIva(rs.getDouble("iva"));
    ord.setQuantitaDigitale(rs.getInt("quantitaDigitale"));
    ord.setQuantitaFisico(rs.getInt("quantitaFisico"));
    ord.setIdUtente(rs.getInt("idUtente"));
    result.add(ord);

  }

} catch (SQLException e) {

  e.printStackTrace();

}


return result;
}
/**
 * {@param} id: int.
 * {@return} ArrayList of Ordine.
 */

public synchronized ArrayList<Ordine> doRetrieveByUser(int id) {

PreparedStatement ps = null;
String query = "SELECT * FROM ordine WHERE idUtente = ?";
ArrayList<Ordine> result = new ArrayList<Ordine>();

try (Connection conn = ConPool.getConnection()) {

  ps = conn.prepareStatement(query);
  ps.setInt(1, id);
  ResultSet rs = ps.executeQuery();
  while (rs.next()) {

    Ordine ord = new Ordine();
    ord.setConsegnato(rs.getBoolean("consegnato"));
    ord.setDataOra(rs.getString("dataOra"));
    ord.setIdOrdine(rs.getInt("idOrdine"));
    ord.setIdProdotto(rs.getInt("idProdotto"));
    ord.setPrezzoFis(rs.getDouble("prezzoFis"));
    ord.setPrezzoDig(rs.getDouble("prezzoDig"));
    ord.setIva(rs.getDouble("iva"));
    ord.setQuantitaDigitale(rs.getInt("quantitaDigitale"));
    ord.setQuantitaFisico(rs.getInt("quantitaFisico"));
    ord.setIdUtente(rs.getInt("idUtente"));
    result.add(ord);

  }

} catch (SQLException e) {

  e.printStackTrace();

}

return result;
}
/**
 * {@param} data1: String.
 * {@param} data2: String.
 * {@return} ArrayList of Ordine.
 */

public synchronized ArrayList<Ordine> doRetrieveByDate(String data1, String data2) {

PreparedStatement ps = null;
String query = "SELECT * FROM ordine WHERE dataOra >= ? AND dataOra <= ?";
ArrayList<Ordine> result = new ArrayList<Ordine>();

try (Connection conn = ConPool.getConnection()) {

  ps = conn.prepareStatement(query);
  ps.setString(1, data1);
  ps.setString(2, data2);
  ResultSet rs = ps.executeQuery();
  while (rs.next()) {

    Ordine ord = new Ordine();
    ord.setConsegnato(rs.getBoolean("consegnato"));
    ord.setDataOra(rs.getString("dataOra"));
    ord.setIdOrdine(rs.getInt("idOrdine"));
    ord.setIdProdotto(rs.getInt("idProdotto"));
    ord.setPrezzoFis(rs.getDouble("prezzoFis"));
    ord.setPrezzoDig(rs.getDouble("prezzoDig"));
    ord.setIva(rs.getDouble("iva"));
    ord.setQuantitaDigitale(rs.getInt("quantitaDigitale"));
    ord.setQuantitaFisico(rs.getInt("quantitaFisico"));
    ord.setIdUtente(rs.getInt("idUtente"));
    result.add(ord);

  }

} catch (SQLException e) {

  e.printStackTrace();

}

 return result;
 }

}

首先从 doRetrieveAll 方法开始,我尝试做一个

@Test
public void doRetrieveAll_Success() throws SQLException {
    assertNotNull(ordineDAO.doRetrieveAll());
}

但我需要知道如何设置 @BeforeAll 才能测试此方法。 你能帮我理解如何正确设置测试类吗?谢谢

【问题讨论】:

  • 从您的 sn-ps 来看,您实际上并不需要 @Before/@BeforeAll 方法 - 您拥有它的方式应该可以工作。

标签: java unit-testing testing junit


【解决方案1】:

您可以使用 PowerMockito 来实现此目的。我提到 PowerMockito 而不是 Mockito 的唯一原因是因为您的 getConnection() 方法是静态的,使用 PowerMockito 模拟静态方法更容易

您需要添加以下依赖项才能使 PowerMockito 正常工作。

    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4-rule</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>

这是测试方法。

import static org.mockito.Matchers.any;
import static org.powermock.api.mockito.PowerMockito.when;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(ConPool.class)
public class OrdineDAOTest {

  @Mock
  private Connection c;

  @Mock
  private PreparedStatement stmt;

  @Mock
  private ResultSet rs;

  @Test
  public void testDoRetrieveAll() {
    try {
      //Mocking the Static ConPool Class 
      PowerMockito.mockStatic(ConPool.class);
      //Making the ConPool.getConnection() method to return Mocked Connection 
      when(ConPool.getConnection()).thenReturn(c);
      //Making the prepareStatement method to return Mocked PrepareStatement 
      when(c.prepareStatement(any(String.class))).thenReturn(stmt);
      // Mocking the Values in ResultSet 
      when(rs.getInt("idOrdine")).thenReturn(10); 
      //This means result set has only one set of result
      //Mocking rs.next() to return true first and then return false the second time
      when(rs.next()).thenReturn(true).thenReturn(false);
      //Making executeQuery() method to return mocked resultset
      when(stmt.executeQuery()).thenReturn(rs);

      OrdineDAO dao = new OrdineDAO();
      // Invoking the actual method from dao
      ArrayList<Ordine> list = dao.doRetrieveAll();
      //Comparing the expected vs actual
      Assert.assertEquals(1, list.size());
      Assert.assertEquals(10, list.get(0).getIdOrdine());
    } catch (Exception e) {
      e.printStackTrace();
    }

  }
}

我已经用注释行解释了代码。

我自己在 java 8 上测试过它以及上面提到的依赖项,一切对我来说都很好。

【讨论】:

    【解决方案2】:

    太棒了!它工作正常,非常感谢。 我想看看如何使用 mockito 创建这个测试用例。 此外,当我测试 doRetrieveByUser 和 doRetrieveByDate 时,我不知道是否必须测试成功/失败场景(传递好/错误的参数),或者我可以以与 doRetrieveAll 测试用例“相同”的方式编写这些测试. 希望清楚。

    【讨论】:

    • 如果工作正常,您必须接受答案。作为单元测试的一部分,您应该始终测试成功和失败的场景
    猜你喜欢
    • 2020-01-17
    • 2011-07-21
    • 2021-03-15
    • 2016-03-15
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    相关资源
    最近更新 更多