
테스트 주도 개발 중 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