Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javadao实现测试_Java_Junit_Dao_Hsqldb_Mockito - Fatal编程技术网

javadao实现测试

javadao实现测试,java,junit,dao,hsqldb,mockito,Java,Junit,Dao,Hsqldb,Mockito,这是一个非常简单的DAO尝试,我想与大家分享 我的问题是,这是否是测试DAO的正确方法。我的意思是,我正在验证SQL查询并给它一个模拟返回。然后告诉mock返回这些特定值并断言它们 我已经将DAO更新为使用准备语句而不是简单语句。谢谢 public class PanelDao implements IO { private final static Logger LOGGER = Logger.getLogger(PanelDao.class); private Conne

这是一个非常简单的DAO尝试,我想与大家分享

我的问题是,这是否是测试DAO的正确方法。我的意思是,我正在验证SQL查询并给它一个模拟返回。然后告诉mock返回这些特定值并断言它们

我已经将DAO更新为使用准备语句而不是简单语句。谢谢

public class PanelDao implements IO {

    private final static Logger LOGGER = Logger.getLogger(PanelDao.class);

    private Connection connection;

    public PanelDao() throws SQLException {
        this(MonetConnector.getConnection()); 
    }

    public PanelDao(Connection connection) throws SQLException {
        this.connection = connection;
    }

    @Override
    public void save(Panel panel) throws SQLException {
        final String query = "INSERT INTO panels VALUES ( ?, ?, ?, ?, ?, ?, ? )";
        final PreparedStatement statement = connection.prepareStatement(query);
        statement.setString(1, panel.getId());
        statement.setString(2, panel.getColor());
        statement.setDate(3, (new Date(panel.getPurchased().getTime())) );
        statement.setDouble(4, panel.getCost());
        statement.setDouble(5, panel.getSellingPrice());
        statement.setBoolean(6, panel.isOnSale());
        statement.setInt(7, panel.getUserId());

        LOGGER.info("Executing: "+query);
        statement.executeUpdate();
    }

    @Override
    public void update(Panel object) {
        throw new UnsupportedOperationException();      
    }

    @Override
    public void delete(Panel object) {
        throw new UnsupportedOperationException();      
    }

    @Override
    public Panel find(String id) throws SQLException {
        final String query = "SELECT * FROM panels WHERE id = ? ";
        final PreparedStatement statement = connection.prepareStatement(query);
        statement.setString(1, id);

        LOGGER.info("Executing: "+query);
        final ResultSet result = statement.executeQuery();

        final Panel panel = new Panel();
        if (result.next()) {
            panel.setId(result.getString("id"));
            panel.setColor(result.getString("color"));
        }
        return panel;       
    }
}
还有考试班

public class PanelDaoTest {

    @InjectMocks
    private PanelDao panelDao;

    @Mock 
    private Connection connection;

    @Mock
    private Statement statement;

    @Mock
    private ResultSet result;

    private Panel panel;

    @BeforeClass
    public static void beforeClass() {
        BasicConfigurator.configure();
    }

    @Before
     public void init() throws SQLException {
        MockitoAnnotations.initMocks(this);
        Mockito.when(connection.createStatement()).thenReturn(statement);
        panel = new Panel("AZ489", "Yellow", new Date(), 10.00, 7.50, true, 1);
    }

   @Test
   public void testSave() throws SQLException {
        Mockito.when(connection.prepareStatement("INSERT INTO panels VALUES ( ?, ?, ?, ?, ?, ?, ? )")).thenReturn(statement);
        panelDao.save(panel);
        Mockito.verify(statement).executeUpdate();
    }

    @Test
    public void testFind() throws SQLException {
        Mockito.when(connection.prepareStatement("SELECT * FROM panels WHERE id = ? ")).thenReturn(statement);
        Mockito.when(statement.executeQuery()).thenReturn(result);
        Mockito.when(result.next()).thenReturn(true);
        Mockito.when(result.getString("id")).thenReturn("AZ489");
        Mockito.when(result.getString("color")).thenReturn("Yellow");
        Panel panel = panelDao.find("AZ489");
        assertEquals("AZ489",panel.getId());
        assertEquals("Yellow",panel.getColor());
        Mockito.verify(statement).executeQuery();
     }
}

2.0使用HSQLDB测试DAO 在考虑了您的反馈后我决定使用HSQLDB进行真正的数据库测试。如果要解决类似问题,请将此作为资源

public class PanelDao implements IO {

    private final static Logger LOGGER = Logger.getLogger(PanelDao.class);

    private Connection connection;

    /**
     * Default constructor is using Monet connector
     */
    public PanelDao() throws SQLException {
        this(MonetConnector.getConnection()); 
    }

    public PanelDao(Connection connection) throws SQLException {
        this.connection = connection;
    }

    @Override
    public void save(Panel panel) throws SQLException {
        final String query = "INSERT INTO panels VALUES ( ?, ?, ?, ?, ?, ?, ? )";
        final PreparedStatement statement = connection.prepareStatement(query);
        statement.setString(1, panel.getId());
        statement.setString(2, panel.getColor());
        statement.setDate(3, (new Date(panel.getPurchased().getTime())) );
        statement.setDouble(4, panel.getCost());
        statement.setDouble(5, panel.getSellingPrice());
        statement.setBoolean(6, panel.isOnSale());
        statement.setInt(7, panel.getUserId());

        LOGGER.info("Executing: "+query);
        statement.executeUpdate();
    }

    @Override
    public void update(Panel object) {
        throw new UnsupportedOperationException();      
    }

    @Override
    public void delete(Panel object) {
        throw new UnsupportedOperationException();      
    }

    @Override
    public Panel find(String id) throws SQLException {
        final String query = "SELECT * FROM panels WHERE id = ? ";
        final PreparedStatement statement = connection.prepareStatement(query);
        statement.setString(1, id);

        LOGGER.info("Executing: "+query);
        final ResultSet result = statement.executeQuery();

        if (result.next()) {
            final Panel panel = new Panel();
            panel.setId(result.getString("id"));
            panel.setColor(result.getString("color"));
            panel.setPurchased(new Date(result.getDate("purchased").getTime()));
            panel.setCost(result.getDouble("cost"));
            panel.setSellingPrice(result.getDouble("selling_price"));
            panel.setOnSale(result.getBoolean("on_sale"));
            panel.setUserId(result.getInt("user_id"));
            return panel;
        }
        return null;        
    }
}
和测试类:

public class PanelDaoTest {

    private PanelDao panelDao;
    private Panel panel;

    /* HSQLDB */
    private static Server server;
    private static Statement statement;
    private static Connection connection;

    @BeforeClass
    public static void beforeClass() throws SQLException {
        BasicConfigurator.configure();
        server = new Server();
        server.setAddress("127.0.0.1");
        server.setDatabaseName(0, "bbtest");
        server.setDatabasePath(0, ".");
        server.setPort(9000);
        server.start();
        PanelDaoTest.connection = DriverManager.getConnection("jdbc:hsqldb:hsql://127.0.0.1:9000/bbtest", "SA", "");
        PanelDaoTest.statement = PanelDaoTest.connection.createStatement();
    }

    @Before
    public void createDatabase() throws SQLException {
        PanelDaoTest.statement.execute(SqlQueries.CREATE_PANEL_TABLE);
        panelDao = new PanelDao(PanelDaoTest.connection);
    }

    @Test
    public void testSave() throws SQLException {
        panel = new Panel();
        panel.setId("A1");
        panel.setPurchased(new Date());
        panelDao.save(panel);
        assertNotNull(panelDao.find("A1"));
    }

    @Test
    public void testFind() throws SQLException {
        final String id = "45ZZE6";
        panel = Panel.getPanel(id);

        Panel received = panelDao.find(id);
        assertNull(received);

        panelDao.save(panel);
        received = panelDao.find(id);
        assertNotNull(received);
        assertEquals(panel.getId(), received.getId());
        assertEquals(panel.getColor(), received.getColor());
        assertEquals(panel.getPurchased().getDate(), received.getPurchased().getDate());
        assertEquals(panel.getPurchased().getMonth(), received.getPurchased().getMonth());
        assertEquals(panel.getPurchased().getYear(), received.getPurchased().getYear());
        assertEquals(panel.getCost(), received.getCost(),0.001);
        assertEquals(panel.getSellingPrice(), received.getSellingPrice(),0.001);
        assertEquals(panel.getUserId(), received.getUserId());
    }

    @After
    public void tearDown() throws SQLException {
        statement.executeUpdate(SqlQueries.DROP_PANEL_TABLE);
    }

    @AfterClass
    public static void stopServer() {
        server.shutdown();
    }
}

我并不认为这种测试方法真的能给你带来什么,而且测试代码非常脆弱。我会使用类似的东西来“模拟”数据库。这实际上可以让您测试查询的正确性。

首先,您不应该通过连接创建SQL查询,因为它容易受到SQL注入的影响。改用
PreparedStatement
s

实际上,以这种方式测试DAO没有多大意义。您的测试只验证DAO正确地来回传递值,但它并没有覆盖DAO发出的SQL查询的正确性所带来的真正复杂性


换句话说,如果您想测试DAO,您需要创建包含真实数据库的集成测试。通过这种方式,您可以验证DAO发出的SQL查询是否正确。

我将使用内存中的数据库(如H2)来测试SQL是否实际工作

  • 当您测试
    save
    方法时,您的测试应该调用
    save
    ,然后从数据库中选择行,并断言那里确实有东西
  • 当您测试
    find
    方法时,您的测试应该直接在数据库中插入一些行,然后调用
    find
    并断言实际找到了所需的行

是的,我会使用事先准备好的语句,谢谢。如果您只使用string concat而不是StringBuilder,并且性能没有变化,那么阅读起来会容易得多。逗号和引号变量也让它变得更加困难。追加(逗号)。追加(引号)而不是追加(“,”)。使用[+“'”+panel时,每一行的可读性都会更高。getXXX()+“,”]这一点是否意味着DAO不应该被模拟,而应该使用真实的数据库或数据库测试框架进行测试?我发现,使用mock,您无法测试sql查询,只能验证我们调用的方法返回的对象是您赋予它返回的对象。。无意义?@locke标准模拟技术在测试服务层时更有用(例如,代码是构成复杂逻辑的部分,或者您需要创建模拟来单独测试类(例如,您希望模拟DAO)。一般来说,大多数DAO包含非常简单的代码,而查询构成了大部分复杂性。在这个场景中,传统的模拟没有那么有用。由于SQL方言和数据库实现的差异,H2可能有点风险。我建议在您将要使用的实际DB平台上设置一个单元测试实例。。。如果您决定使用H2,请确保设置适当的参数。@ach这是非常合理的建议。我的经验表明,H2和其他平台在SQL等方面的差异相当小,特别是如果您选择了正确的兼容模式。如果您的SQL中有bug,那么针对H2的测试将发现它们,100次中有99次。相比之下,需要设置一个“真实”的数据库实例会使JUnit或TestNG测试更加笨拙、缓慢,并且更难管理。当然,这两种方法都有优缺点;这可能是“做适合你的事”的情况之一。@DavidWallace,用你的句子(如果SQL中有bug,那么对H2的测试会发现它们,100次中有99次)。它不再是单元测试。要成为一个合适的单元测试,您必须在每次运行时都信任它。@frantakocurek您完全正确。这就是为什么我没有称之为单元测试。另外,我的意思是100个SQL错误中有99个会被使用H2的测试发现——我并不是说这些测试的行为是不确定的。使用内存中数据库的好处之一是可以使测试具有确定性。