테스트 주도 개발 중 TDD
TDD(Test-Driven Developmen) : 본 코드 작성 > 테스트 코드에서 실행 > 눈으로 검증
테스트 코드에서는 파라미터를 입력하지 않음
메서드 사용 방법을 모르면 요청하고 리턴받는 것을 이해할 수 없음
1. BankDAO에 본 코드 작성하기 - insert, delete, update
package dao; import db.DBConnection; import java.sql.Connection; import java.sql.PreparedStatement; /* * DAO - Data Access Object * SRP - 단일 책임의 원칙*/ public class BankDAO { public int deleteByNumber(int number){ Connection conn = DBConnection.getInstance(); // 소켓을 가져옴 try { String sql = "delete from account_tb where number = ?"; // 쿼리이기에 DB표기법 사용 PreparedStatement pstmt = conn.prepareStatement(sql); // 쿼리를 버퍼에 담음 pstmt.setInt(1, number); // 완성시킴 int num = pstmt.executeUpdate(); // flush함 return num; } catch (Exception e) { e.printStackTrace(); return -1; // 오류값 리턴 } } public int insertByNumber(String password,int balance){ Connection conn = DBConnection.getInstance(); try { String sql = "insert into account_tb(password, balance, created_at) values(?, ?, now())"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, password); pstmt.setInt(2, balance); int num = pstmt.executeUpdate(); return num; // 1이 리턴됐을 때 성공 그외는 다 실패 } catch (Exception e) { e.printStackTrace(); return -1; // 오류값 리턴 } } public int updateByNumber(int balance, int number){ Connection conn = DBConnection.getInstance(); try { String sql = "update account_tb set balance = ? where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, balance); pstmt.setInt(2, number); int num = pstmt.executeUpdate(); return num; // 1이 리턴됐을 때 성공 그외는 다 실패 } catch (Exception e) { e.printStackTrace(); return -1; // 오류값 리턴 } } public void selectByNumber(){} public void selectAll(){} }
DB와 자바의 표기법
데이터베이스의 표기법 : _ (언더스코어)
자바의 표기법 : 카멜 표기법(띄워쓰기시 대문자로 구분)
2. Test 실행 - insert, delete, update
package dao; import org.junit.jupiter.api.Test; public class BankDAOTest { @Test //어노테이션 : 실행가능 public void deleteByNumber_test(){ //given int number = 3; //when BankDAO dao = new BankDAO(); int result = dao.deleteByNumber(number); //then if(result == 1) { System.out.println("삭제 성공"); } else if(result == 0) { System.out.println(number+"번호를 찾을 수 없습니다"); } else { System.out.println("삭제 실패"); } } @Test public void insertByNumber_test(){ //given String password= "1234"; int balance = 5000; //when BankDAO dao = new BankDAO(); int result = dao.insertByNumber(password,balance); //then if(result == 1) { System.out.println("삽입 성공"); } else { System.out.println("삽입 실패"); } } @Test public void updateByNumber(){ //given int balance = 5000; int number = 5; //when BankDAO dao = new BankDAO(); int result = dao.updateByNumber(balance,number); //then if(result == 1){ System.out.println("수정 성공"); }else { System.out.println("수정 실패"); } } }
3. BankApp에서 데이터를 받아서 delete문 실행시키기
import dao.BankDAO; import db.DBConnection; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.Scanner; public class BankApp { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("삭제할 계좌번호를 입력해주세요 : "); int number = sc.nextInt(); BankDAO dao = new BankDAO(); int result = dao.deleteByNumber(number); if (result == 1) { System.out.println("삭제 성공했습니다."); } else { System.out.println("삭제 실패했습니다."); } } }
4. select문
package dao; import db.DBConnection; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; /* * DAO - Data Access Object * SRP - 단일 책임의 원칙*/ public class BankDAO { public void selectByNumber(int number){ Connection conn = DBConnection.getInstance(); try{ String sql = "select * from account_tb where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, number); ResultSet rs = pstmt.executeQuery(); boolean isRow = rs.next(); // 커서를 컬럼자리에서 한칸 내림 //System.out.println(isRow); System.out.println(rs.getInt("number")); System.out.println(rs.getString("password")); System.out.println(rs.getInt("balance")); System.out.println(rs.getTimestamp("created_at")); }catch (Exception e){ e.printStackTrace(); } } public void selectAll(){ } }
NOW를 사용할 때 조심할 점
- 자바에서 now 넣는 것과 쿼리에 now를 넣었을 때 완전 달라질 수 있음
예시) 자바 서버는 한국, 데이터 베이스 서버가 미국일 경우
DB에서 now 하면 미국 시간이 들어오고
자바 코드로 localdatetime하면 한국 시간이 들어옴
→ 시간은 민감함! 조심!
rs.next() : ResultSet 객체에서 다음 행으로 이동하고 해당 행이 존재하는지 여부를 확인
컬럼에서 시작해서 true면 한 칸 내려가고 false면 더 이상 데이터가 없음
커서를 들고 있음 = Git의 헤더 같은 것
프로젝션(Projection) : 컬럼을 찝어내는 것
특정 테이블의 일부 열을 선택하여 결과로 반환하는 작업
5. select문 테스트 실행하기
package dao; import model.Account; import org.junit.jupiter.api.Test; public class BankDAOTest { @Test public void selectByNumber_test(){ //given int number = 1; //when BankDAO dao = new BankDAO(); Account account = dao.selectByNumber(number); if (account == null) { System.out.println(number + "로 조회된 값이 없습니다"); } else { System.out.println(account.getNumber()); System.out.println(account.getPassword()); System.out.println(account.getBalbance()); System.out.println(account.getCreatedAt()); } } }
데이터베이스로 부터 데이터를 가져와서 오브젝트로 파싱함
한 건을 조회한 것은 클래스에 담을 수 있음
4건을 조회하면 커서 4번 내려야 함
전체 조회시 거꾸로 조회함 → desc : 내림 차순!
데이터베이스에 몇 건의 데이터가 있는지 알 수 가 없음 → while을 false까지 돌려야 함
다 같은 타입이 연속적으로 있기 때문에 벡터, 컬렉션에 담아야함
- 연속적인 데이터 : 벡터 / 선
- 하나의 데이터 : 스칼라 / 점
- 가로와 세로가 있으면 메트릭스
package dao; import db.DBConnection; import model.Account; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; /* * DAO - Data Access Object * SRP - 단일 책임의 원칙*/ public class BankDAO { public int deleteByNumber(int number){ Connection conn = DBConnection.getInstance(); // 소켓을 가져옴 try { String sql = "delete from account_tb where number = ?;"; // 쿼리 PreparedStatement pstmt = conn.prepareStatement(sql); // 쿼리를 버퍼에 담음 pstmt.setInt(1, number); // 완성시킴 int num = pstmt.executeUpdate(); // flush함 return num; } catch (Exception e) { e.printStackTrace(); } return -1; // 오류값 리턴 } public int insertByNumber(String password,int balance){ Connection conn = DBConnection.getInstance(); try { String sql = "insert into account_tb(password, balance, created_at) values(?, ?, now())"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, password); pstmt.setInt(2, balance); int num = pstmt.executeUpdate(); return num; // 1이 리턴됐을 때 성공 그외는 다 실패 } catch (Exception e) { e.printStackTrace(); } return -1; // 오류값 리턴 } public int updateByNumber(int balance, int number){ Connection conn = DBConnection.getInstance(); try { String sql = "update account_tb set balance = ? where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, balance); pstmt.setInt(2, number); int num = pstmt.executeUpdate(); return num; // 1이 리턴됐을 때 성공 그외는 다 실패 } catch (Exception e) { e.printStackTrace(); } return -1; // 오류값 리턴 } public Account selectByNumber(int number){ Connection conn = DBConnection.getInstance(); try{ String sql = "select * from account_tb where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, number); ResultSet rs = pstmt.executeQuery(); //boolean isRow = rs.next(); 커서를 컬럼자리에서 한칸 내림 //System.out.println(isRow); if(rs.next() == true) { Account account = new Account( rs.getInt("number"), rs.getString("password"), rs.getInt("balance"), rs.getTimestamp("created_at") ); return account; } //System.out.println(rs.getInt("number")); // System.out.println(rs.getString("password")); //System.out.println(rs.getInt("balance")); //System.out.println(rs.getTimestamp("created_at")); }catch (Exception e){ e.printStackTrace(); } return null; } public List<Account> selectAll(){ Connection conn = DBConnection.getInstance(); try{ String sql = "select * from account_tb order by number desc"; PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); List<Account> accountList = new ArrayList<>(); while(rs.next() == true) { Account account = new Account( rs.getInt("number"), rs.getString("password"), rs.getInt("balance"), rs.getTimestamp("created_at") ); accountList.add(account); } return accountList; }catch (Exception e){ e.printStackTrace(); } return null; } }
package dao; import model.Account; import org.junit.jupiter.api.Test; import java.sql.SQLOutput; import java.util.List; public class BankDAOTest { @Test public void selectAll_test(){ //given //when BankDAO dao = new BankDAO(); List<Account> accountList = dao.selectAll(); //System.out.println(accountList.size()); System.out.println(accountList); } @Test public void selectByNumber_test(){ //given int number = 1; //when BankDAO dao = new BankDAO(); Account account = dao.selectByNumber(number); if (account == null) { System.out.println(number + "로 조회된 값이 없습니다"); } else { System.out.println(account); // System.out.println(account.getNumber()); // System.out.println(account.getPassword()); // System.out.println(account.getBalbance()); // System.out.println(account.getCreatedAt()); } } @Test public void deleteByNumber_test(){ //given int number = 3; //when BankDAO dao = new BankDAO(); int result = dao.deleteByNumber(number); //then if(result == 1) { System.out.println("삭제 성공"); } else if(result == 0) { System.out.println(number+"번호를 찾을 수 없습니다"); } else { System.out.println("삭제 실패"); } } @Test public void insertByNumber_test(){ //given String password= "1234"; int balance = 5000; //when BankDAO dao = new BankDAO(); int result = dao.insertByNumber(password,balance); //then if(result == 1) { System.out.println("삽입 성공"); } else { System.out.println("삽입 실패"); } } @Test public void updateByNumber(){ //given int balance = 5000; int number = 5; //when BankDAO dao = new BankDAO(); int result = dao.updateByNumber(balance,number); //then if(result == 1){ System.out.println("수정 성공"); }else { System.out.println("수정 실패"); } } }
package model; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import java.sql.Timestamp; /* * DBDP Select 한 데이터를 다기 위한 오브젝트 */ @ToString @AllArgsConstructor @Getter public class Account { private int number; private String password; private int balbance; //java.sql의 Timestamp private Timestamp createdAt; }
Share article