E D R , A S I H C RSS

Test Driven Database Development

TDD 둜 Database Programming 을 μ§„ν–‰ν•˜λŠ” 방법 & κ²½ν—˜λ“€.
See Also TdddArticle

1002의 경우 TDD 둜 DB 뢀뢄을 λ§Œλ“€λ•Œ μ–΄λ–»κ²Œ μ§„ν–‰λ κΉŒ κΆλ¦¬ν•˜λ˜μ€‘ λ‘κ°€μ§€λΌ μ‹€ν—˜ν•΄λ³΄μ•˜λ‹€. 보톡은 TDD둜 DB 뢀뢄을 λ§Œλ“€λ•Œ DB Repository 뢀뢄에 λŒ€ν•΄μ„œ MockObject λΌ λ§Œλ“€μ§€λ§Œ, λ‹€μŒμ€ Mock 을 μ•ˆλ§Œλ“€κ³  μž‘μ„±ν•΄λ΄€λ‹€. μ–΄λ–€ 일이 μΌμ–΄λ‚ κΉŒλΌ μƒκ°ν•˜λ©°.
~cpp 

import junit.framework.TestCase;

import java.sql.*;

public class SpikeRepositoryTest extends TestCase {
    private Connection con;
    protected IRepository repository;
    private String writer;
    private String title;
    private String body;

    public void setUp() throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
        initConnection();
        repository= new SpikeRepository(con);
        repository.initialize();

        writer = "writer";
        title = "title";
        body = "body";
    }

    public void tearDown() throws SQLException {
        repository.destroy();
        uninitConnection();
    }

    public void testEdit() throws SQLException {
        repository.createArticle(writer, title, body);
        String writerEdited = "writerEdited";
        String titleEdited = "titleEdited";
        String bodyEdited = "bodyEdited";
        repository.edit(1, writerEdited, titleEdited, bodyEdited);
        Article article = repository.get(1);
        assertEquals (writerEdited, article.getWriter());
        assertEquals (titleEdited, article.getTitle());
        assertEquals (bodyEdited, article.getBody());
    }

    public void testTotalArticle() throws SQLException {
        repository.createArticle(writer, title, body);
        assertEquals (1, repository.getTotalArticle());
    }

    public void testCreateArticle() throws SQLException {
        repository.createArticle(writer, title, body);
        assertEquals (1, repository.getTotalArticle());
    }

    public void testDelete() throws SQLException {
        repository.createArticle(writer, title, body);
        repository.delete(1);
        assertEquals (0, repository.getTotalArticle());
    }

    public void testGet() throws SQLException {
        repository.createArticle(writer, title, body);
        Article article2 = repository.get(1);
        assertEquals(writer, article2.getWriter());
    }

    public void testArticleTableInitialize() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
        repository = new SpikeRepository(con);
        repository.initialize();

        String articleTableName = "articlelist";

        String sqlStr="select id, writer, title, body from " + articleTableName;
        PreparedStatement pstmt= con.prepareStatement(sqlStr);
        ResultSet rs = pstmt.executeQuery();

        assertEquals (0, rs.getRow());
    }

    private void initConnection() throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
        String hostname = "localhost";
        String dbname = "reset";
        String userId = "reset";
        String userPass = "reset";
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        String url="jdbc:mysql://"+hostname+"/"+dbname+"?user="+userId+"&password="+userPass;
        con = DriverManager.getConnection(url);
    }

    private void uninitConnection() throws SQLException {
        con.close();
    }

    public void testDuplicatedInitialize() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        repository.initialize();
        repository.initialize();
        repository.initialize();
        repository.destroy();
    }
}

μž‘μ„±ν•˜λŠ”μ€‘μ—, DB에 직접 μ ‘μ†ν•΄μ„œ ν™•μΈν•˜λŠ” μ½”λ“œκ°€ ν…ŒμŠ€νŠΈμ— λ“œλŸ¬λ‚¬λ‹€. (μ΄λŠ” μ˜ˆμƒν•œ 일이긴 ν•˜λ‹€. DB 에 비쒅속적인 interface λΌ μ œμ™Έν•˜λ”λΌλ„ DB μͺ½ μ½”λ“œλΌ κ³„μ† μŒ“μ•„κ°€κΈ° μœ„ν•΄μ„  DB μ½”λ“œλΌ μ–΄λŠμ •λ„ 써야 ν•œλ‹€.) 처음 DB 에 직접 λ°μ΄ν„°λΌ λ„£μ„λ•ŒλŠ” side-effectκ°€ λ°œμƒν•˜λ€λ‘œ, ν…ŒμŠ€νŠΈλΌ 2λ²ˆμ”© λŒλ €μ€˜μ„œ side-effectλΌ ν™•μΈμ„ ν–ˆλ‹€. 점차적으둜 initialize λ©”μ†Œλ“œμ™€ destroy λ©”μ†Œλ“œλΌ λ§Œλ“€κ³  μ΄λΌ setUp, tearDown μͺ½μ— λ„£μ–΄μ€ŒμœΌλ‘œ ν…ŒμŠ€νŠΈμ‹œμ˜ side-effectλΌ ν•΄κ²°ν•΄λ‚˜κ°”λ‹€.

ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜λ‹€κ°€, 만일 μ—¬κΈ°μ„œλΆ€ν„° interface λΌ μΆ”μΆœν•œλ’€μ— 거꾸둜 MockRepository λΌ λ§Œλ“€ 수 μžˆμ„κΉŒ ν•˜λŠ” 생각을 ν–ˆλ‹€. (interface λΌ μΆ”μΆœν•¨μœΌλ‘œμ„œ 같은 λ©”μ†Œλ“œμ— λŒ€ν•΄ λ‹€λ₯Έ μ„±κ²©μ˜ Repository, 즉 File Based λ‚˜ λ‹€λ₯Έ μ„œλ²„ λ‘œλΆ€ν„° λ°μ΄ν„°λΌ μ–»μ–΄μ˜€λŠ” Repository λ“± λ‹€ν˜•μ„±μ„ 생각해볼 수 μžˆλŠ” 것이닀.)
κ²°κ³ΌλŠ” λ‹€μŒμ˜ λ¬Έμ œκ°€ λ°œμƒν•˜μ˜€λ‹€. λ°”λ‘œ, interface 에 DB Exception λ˜μ§„κ²ƒλ“€μ΄ λ¬»μ–΄λ‚˜λŠ”κ²ƒμ΄λ‹€.
~cpp 

import java.sql.SQLException;

public interface IRepository {
    Article get(int index) throws SQLException;

    void initialize() throws SQLException;

    void destroy() throws SQLException;

    void edit(int index, String writer, String title, String body) throws SQLException;

    int getTotalArticle() throws SQLException;

    void createArticle(String writer, String title, String body) throws SQLException;

    void delete(int index);
}
즉, MockRepository μ—μ„œλŠ” Exception 을 던질 ν•„μš”κ°€ μ—†λŠ”λ°, λ©”μ†Œλ“œλ§ˆλ‹€ μ „λΆ€ throw λΌ λ˜μ Έμ€˜μ•Ό ν•œλ‹€. (ν•œνŽΈμœΌλ‘œλŠ”, λ‹€λ₯Έ μ–Έμ–΄μ—μ„œλŠ” μƒκ΄€μ—†λŠ”λ° Java μ—μ„œμ˜ Checked Exception 의 λ¬Έμ œμΌλŸ°μ§€λ„ λͺ¨λ₯΄κ² λ‹€.

만일 MockRepositoryλΌ λ¨Όμ € λ§Œλ“ λ‹€λ©΄? interface λΌ μΆ”μΆœν•œ μˆœκ°„μ—λŠ” λ¬Έμ œκ°€ μ—†κ² μ§€λ§Œ, λ‹€μŒμ— DBRepository λΌ λ§Œλ“€λ•Œκ°€ λ¬Έμ œκ°€ λœλ‹€. interface 의 μ •μ˜μ—μ„œλŠ” μ˜ˆμ™ΈλΌ λ˜μ§€μ§€ μ•ŠμœΌλ€λ‘œ, interface λΌ λ‹€μ‹œ μˆ˜μ •ν•˜λ˜μ§€, μ•„λ‹ˆλ©΄ SQL κ΄€λ ¨ Exception 을 μ „λΆ€ ν•΄λ‹Ή λ©”μ†Œλ“œ μ•ˆμ—μ„œ try-catch 둜 μž‘μ•„λ‚΄μ•Ό ν•œλ‹€. 즉, Database μ—μ„œμ˜ μ˜ˆμ™Έμ²˜λ¦¬λ“€μ— λŒ€ν•΄ μ „λΆ€ Repository μ•ˆμ—μ„œ μžμ²΄ν•΄κ²°μ„ ν•˜κ²Œλ” κ°•μš”ν•˜λŠ” μ½”λ“œκ°€ λ‚˜μ˜¨λ‹€.

μ–΄λ–€ 것이 μ˜¬λ°”λ₯Έ 일일까. --1002

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:28:11
Processing time 0.0178 sec