본문 바로가기
JAVA

[JAVA ] JDBC 활용한 미니 프로젝트 - 2단계

by 방준이 2021. 9. 19.
반응형

0. 계좌관리 프로그램

해당 프로젝트는 KOSTA EDU 교육에서 진행하는 수업의 일부를 공부하는 목적으로 올리는 용도입니다 :) 단계별로 프로젝트를 실습할 예정이며 TestUnit 클래스를 먼저 만들고 여러 가지 예외적인 상황에 대해서 생각해 본 후 해당 기능을 구현하는 순서로 진행하였습니다. 참고로 TestUnit 클래스는 하나의 기능을 테스트하는 목적으로 설계된 클래스입니다.

 

1.  잔액조회 기능 구현 전 TestUnit Class 작성하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package test;
 
import java.sql.SQLException;
import model.AccountDAO;
import model.NotMatchedPasswordException;
import model.AccountNotFoundException;
 
//step2 계좌 잔액조회 테스트
public class TestUnit2 {
    public static void main(String[] args) {        
        try {
            AccountDAO dao = new AccountDAO();
            //1. AccountNotFoundException test : 존재하지 않는 계좌번호 입력 
            //System.out.println("잔액조회:"+ dao.findBalanceByAccountNo("11", "1234"));
            
            //2.NotMatchedPasswordException test: 잘못된 비번입력  
          //System.out.println("잔액조회:"+ dao.findBalanceByAccountNo("1", "1235"));
            
            //3.잔액조회 정상흐름 실행         
            System.out.println("잔액조회:"+ dao.findBalanceByAccountNo("1""1234"));
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (AccountNotFoundException e) {
            e.printStackTrace();
        } catch (NotMatchedPasswordException e) {
            e.printStackTrace();
        } 
    }
}
 
 

 

이번에도 마찬가지로 TestUnit2 클래스를 먼저 정의하여 어떤 방식으로 메서드(기능)를 호출해야 할지를 생각해 본후  잔액조회 기능(findBalanceByAccountNo) 을 구현하였다. 요구사항 5번에 맞게 계좌번호가 존재해야 하며 그에 맞는 비밀번호가 일치해야 한다. 그렇다면 예외적인 상황으로 계좌가 존재하지 않는경우와 비밀번호가 일치하지 않는 경우로 예외적인 상황을 연출할 수 있다. 위의 코드에서도 마찬가지로 예외적인 상황 2개, 정상적인 상황 1개로 Test를 작성해보았다.

 

 

2. 잔액조회 기능 구현 findBalanceByAccountNo()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public int findBalanceByAccountNo(String accountNo, String password) throws AccountNotFoundException, SQLException, NotMatchedPasswordException {
            
    AccountVO vo = null;
    Connection con=null;
    PreparedStatement pstmt=null;
    ResultSet rs=null;
    try {
        con=getConnection();
        String sql="select * from account where ACCOUNT_NO = ?";
        pstmt=con.prepareStatement(sql);
        pstmt.setString(1, accountNo);
        rs=pstmt.executeQuery();
        if(rs.next()) {
            vo = new AccountVO(rs.getString(1), rs.getString(2), rs.getString(3), rs.getInt(4));
        }
        else
            throw new AccountNotFoundException("계좌가 존재하지 않습니다.");
        // 계좌번호가 일치하지 않는 경우
        if(!vo.getPassword().equals(password)) throw new NotMatchedPasswordException("비밀번호가 일치하지 않습니다.");
        return vo.getBalance();
       
    }finally {
        closeAll(rs, pstmt, con);
    }
}
cs

 

위의 코드는 불필요한 정보도 같이 가져오게끔 코드를 구현하였다. DB에서 데이터를 받아오는 경우에도 간단히 password와 balance 정보만 가져오면 되는 것을 * 를 이용하여 모든 속성을 가져왔다. 또한 AccountVO 객체를 불필요하게 만들게 되었고 이에 따른 불필요한 코드가 추가되었다. 따라서 단순하게 int형의 balance 변수를 반환하게 코드를 작성해보자. 

 

 

2 - 2) 잔액조회 기능 구현 findBalanceByAccountNo() 리팩토링

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public int findBalanceByAccountNo(String accountNo, String password) throws AccountNotFoundException, SQLException, NotMatchedPasswordException {
            
    int balance = 0
    Connection con=null;
    PreparedStatement pstmt=null;
    ResultSet rs=null;
    try {
        con=getConnection();
        String sql="select password, balance from account where ACCOUNT_NO = ?";
        pstmt=con.prepareStatement(sql);
        pstmt.setString(1, accountNo);
        rs=pstmt.executeQuery();
        if(rs.next()) {
            balance = rs.getInt(2);
        }
        else
            throw new AccountNotFoundException("계좌가 존재하지 않습니다.");
        // 계좌번호가 일치하지 않는 경우
        if(!rs.getString(1).equals(password)) throw new NotMatchedPasswordException("비밀번호가 일치하지 않습니다.");
        return balance;
        
    }finally {
        closeAll(rs, pstmt, con);
    }
}    
cs

 

 

3. 요구사항 6~7 입금하기 구현 전 TestUnit Class 작성하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package test;
 
import java.sql.SQLException;
import model.AccountDAO;
import model.NoMoneyException;
import model.NotMatchedPasswordException;
import model.AccountNotFoundException;
 
public class TestUnit3 {
    public static void main(String[] args) {
        try {
 
            AccountDAO dao = new AccountDAO();
            // 대안흐름 테스트
            String accountNo = "12";       // 존재하지 않는 계좌번호
            String password = "12341";       // 패스워드 테스트
            int money = 1000;
            dao.deposit(accountNo, password, money);
            System.out.println("입금완료");
 
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch(NoMoneyException e) {
            System.out.println(e.getMessage());
        } catch(NotMatchedPasswordException e) {
            System.out.println(e.getMessage());
        }  catch(SQLException e) {
            e.printStackTrace();
        } catch (model.AccountNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 
 

 

TestUnit3의 경우 위와 같이 구현하였다. TestCase로 생각해 볼 수 있는 경우는 계좌가 존재하지 않는 경우와 패스워드가 일치하지 않는 경우가 있다. 이는 findBalanceByAccountNo() 메서드를 재사용함으로써 코드의 중복을 피할 수 있다. 또한 요구사항 6에 맞게 입금액이 0원 초과이어야 하므로 입금액이 0원인 경우도 테스트케이스로 작성해 볼 수 있을 것이다.  위의 테스트 케이스에 맞게 deposit() 메서드를 작성해보자.  

 

4. 입금하기 기능 구현하기 deposit()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * 계좌에 입금하는 메서드
 * 입금액이 0원 이하이면 NomoneyException 발생시키고 throw
 * 계좌번호에 존재하지 않으면 AccountNotFoundException 발생시키고 throw
 * 패스워드가 일치하지 않으면 NotMatchedPasswordException을 발생시키고 throw
 * 입금액이 0원을 초과하고 계좌번호 존재하고 패스워드 일치하면 입급처리
 * @param accountNo
 * @param password
 * @param money
 * @throws NoMoneyException 
 * @throws SQLException 
 * @throws NotMatchedPasswordException 
 * @throws AccountNotFoundException 
 */
public void deposit(String accountNo, String password, int money) throws NoMoneyException, SQLException, AccountNotFoundException, NotMatchedPasswordException {
    
    if (money <= 0throw new NoMoneyException("입금액이 0원 이하입니다.");
    
    Connection con=null;
    PreparedStatement pstmt=null;
    ResultSet rs=null;
    
    try {
        con = getConnection();
      findBalanceByAccountNo(accountNo, password);
        String sql = "update account set balance=balance + ? where account_no=?";
        pstmt=con.prepareStatement(sql);
        pstmt.setInt(1, money);
        pstmt.setString(2, accountNo);
        rs=pstmt.executeQuery();
    } finally {
        closeAll(rs, pstmt, con);
    }
}
cs

 

입금하기 (deposit())  기능을 구현함에 있어서 우선 입금액이 0원인지 간단하게 확인해 볼 수 있을것이다. 0원이 이하인 경우 정의해놓은 예외를 throw 해주었다. 또한 계좌번호가 존재하지 않거나 비밀번호가 일치하지 않는 경우 잔액 조회 기능 메서드(findBalanceByAccountNo())를 이용해서 코드의 중복을 제거해주었다. 다음 단계로 매개변수 입력으로 money 만큼 balance 속성을 update 시켜주면 되므로 String sql = "update account set balance=balance + ? where account_no=?"  sql 명령문으로 해당 계좌번호에 맞는 데이터의 balance 속성의 값을 업데이트 시켜주었다. 

 

 

5.  기능의 분할 checkAccountNoAndPassword()

잔액조회 기능 (findBalanceByAccountNo), 입금하기 기능(deposit)을 구현함에 있어서 코드의 중복이 발생한 것을 알 수 있다. 중복되는 코드는 밑의 그림과 같이 계좌번호가 존재하는지 DB를 조회한 후 해당 계좌번호가 존재한다면 해당 비밀번호를 가져와 입력한 비밀번호와 비교하는 작업을 거친다는 것을 알 수 있다. 이 부분을 따로 함수로 분할해서 역할에 부합하는 메서드를 정의해보자.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void checkAccountNoAndPassword(String accountNo, String password) throws SQLException, NotMatchedPasswordException, AccountNotFoundException {
    Connection con = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        con = getConnection();
        String sql = "select password from account where account_no = ?";
        pstmt = con.prepareStatement(sql);
        pstmt.setString(1, accountNo);
        rs = pstmt.executeQuery();
        if (rs.next()) {
            if(!rs.getString(1).equals(password)) throw new NotMatchedPasswordException("계좌 비밀번호가 일치하지 않습니다");
        }
        else throw new AccountNotFoundException(accountNo + " 해당 계좌번호를 찾을 수 없습니다.");
    } finally {
        closeAll(rs, pstmt, con);
    }
}
 
cs

 

위의 소스코드가 계좌번호의 유무를 확인하고 존재한다면 password가 일치하는지 검사하는 메서드이다. 여기서 핵심이 되는 곳은 String sql = "select password from account where account_no = ?"  sql 문이다. 해당 계좌번호가 존재한다면 rs.next()는 true를 반환할 것이고 이어서 패스워드를 비교하면 된다. 이어서 패스워드가 일치하지 않는다면 NotMatchedPasswordException 예외가 발생할 것이고 그렇지 않다면 정상적으로 메서드를 마무리할 것이다. 정리 하면 잔액조회나 입금하기 기능에서 계좌번호의 유무와 패스워드 조회하는 기능을 중복해서 사용한다. 이를 메서드(기능) 단위로 분리하였고 이 함수를 호출하고 예외가 발생하지 않는다면 계좌번호와 비밀번호가 일치한다는 것이다.

 

 

 

 

 

 

 

반응형