5

これは、共有したい非常に単純な DAO の試みです。

私の質問は、これが DAO をテストする正しい方法かどうかです。つまり、SQL クエリを検証してモックを返すということです。次に、これらの特定の値を返してアサートするようにモックに指示しますか?

単純なステートメントの代わりに準備済みステートメントを使用するように 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();
    }
}
4

3 に答える 3

6

まず第一に、SQL インジェクションに対して脆弱であるため、連結によって SQL クエリを作成しないでください。PreparedStatement代わりに s を使用してください。

実際、この方法で DAO をテストしても意味がありません。テストでは、DAO が値を正しくやり取りすることのみを確認しますが、DAO によって発行された SQL クエリの正確さにある実際の複雑さはカバーしていません。

つまり、DAO をテストする場合は、実際のデータベースを含む統合テストを作成する必要があります。このようにして、DAO によって発行された SQL クエリが正しいことを確認できます。

于 2012-11-29T16:53:31.117 に答える
5

テストの方法が実際に何かを買っているとは本当に思いませんし、テストコードは非常に脆弱です。データベースを「モック」できるDBUnitのようなものを使用します。これにより、実際にクエリの正確性をテストできます。

于 2012-11-29T16:50:00.883 に答える
4

H2 などのメモリ内データベースを使用して、SQL が実際に機能することをテストします。

  • メソッドをテストするときはsave、テストで を呼び出しsaveてから、データベースから行を選択し、そこに実際に何かがあることをアサートする必要があります。
  • メソッドをテストするときは、テストでデータベースにいくつかの行を直接挿入してから、目的の行が実際に見つかったことをfind呼び出してアサートする必要があります。find
于 2012-11-29T21:17:15.857 に答える