1. [입력] 게임에 참여할 사람의 이름을 입력 받는다.(쉼표 기준으로 분리)
[예외처리] 쉼표 외의 다른 문자를 구분자로 한 경우 IllegalArgumentException 예외를 발생시킨다.
[예외처리] 입력값이 공백일 경우 IllegalArgumentException 예외를 발생시킨다.
2. [입력] 게임에 참여한 사람의 배팅 금액을 입력 받는다.
[예외처리] 입력값이 공백일 경우 IllegalArgumentException 예외를 발생시킨다.
[예외처리] 입력값이 숫자가 아닐 경우 IllegalArgumentException 예외를 발생시킨다.
[예외처리] 입력값이 0 이하일 경우 IllegalArgumentException 예외를 발생시킨다.
3. [중간 과정] 딜러와 사용자에게 카드를 2장씩 나누어준다.
[카드 조건] 덱은 1개만 사용한다.(A ~ K : 13 * 4 = 52장)
4. [중간 과정] 딜러와 사용자의 최초 카드 합계를 구하며, 블랙잭 여부를 판단한다.
[ACE 조건] ACE가 11이어도 21이 넘지 않는 경우에는 11, 넘는 경우에는 1로 계산한다.
5. [출력] 카드 현황을 출력한다.
[출력 조건] 딜러는 첫 번째 카드만 출력한다.
6. [입력] 사용자별로 카드 추가 지급 여부를 입력 받는다.
[예외처리] y, n 외의 다른 문자일 경우 IllegalArgumentException 예외를 발생시킨다.
[입력 조건] 모든 사용자가 추가 지급을 완료할 때까지 반복한다.
[지급 조건] 사용자가 y를 입력하고, 사용자의 현재 카드 합계가 21미만일 경우에 카드를 지급한다.
7. [출력] 사용자별로 지급 현황을 출력한다.
8. [출력] 딜러의 카드 합계가 17 이상이 일 될 때까지 추가 지급 현황을 출력한다.
9. [출력] 사용자별 카드 현황 및 결과를 출력한다.
10. [중간 과정] 최종 승패 및 수익을 계산한다.
11. [출력] 참여자별 최종 수익을 출력한다.
- 사용자의 이름을 검증하는 거니까 User 클래스의 기능으로 분류하자.
- 쉼표 외의 다른 문자를 구분자로 한 경우를 검증하기 위해 검증 클래스를 만들어야 해.
- 쉼표로 문자열을 구분하는 클래스니까 CommaSplitter를 클래스명으로 하고, CommaSpliiterTest를 만들자.

- 테스트 케이스를 생각하자.
- 공백이 입력되는 경우 예외 발생
- 구분자가 쉼표가 아닌 경우 예외 발생 -> 이건 User 클래스에서 이름 검증할 때 하자. ex) 이름에 특수문자가 포함될 수 없습니다.
- 문자열을 쉼표로 올바르게 구분하여 리스트로 반환 테스트
- 입력값이 공백일 경우 예외를 발생시키는 테스트를 작성하자.
- 문자열을 쉼표로 구분하여 리스트로 올바르게 반환하는지 테스트하자.
- 구현하다 보니 CommaSplitter에서
pobi , jason을 입력받는 경우 User에 공백이 포함된 이름이 들어간다. User 생성자로 들어오는 input에 대해 문자열 양 쪽 공백을 제거하는 코드를 추가하자.
- 쉼표로 문자열을 구분하는 클래스니까 CommaSplitter를 클래스명으로 하고, CommaSpliiterTest를 만들자.
- 배팅 금액의 클래스명은 BettingAmount로 하자.
- 우선 BettingAmountTest 클래스를 생성하자.

- 배팅 금액이 공백인 경우를 테스트하자.
- 배팅 금액이 숫자 타입이 아닐 경우를 테스트하자.
- 배팅 금액이 0 이하인 경우를 테스트하자.
-
어, 기능 목록 3에서 나오는 도메인은 카드라고 생각하면 될 거 같은데, 카드 도메인에는 딱히 로직이 없는데 어떻게 TDD로 구현하지? 얘는 그냥 바로 만들어도 되나?
-
별다른 도메인 로직이 존재하지 않는 값객체는 도메인 규칙을 정의하는 용도로 TDD를 진행하자.
-
Card 객체는 필드로 Rank와 Suit을 가지고 있다. 이 두 클래스 먼저 TDD를 진행하자.(사전에 한 설계를 가지고 TDD를 하는 것이기 때문에 이렇게 바로 필드 구조가 나온 것. 만약 처음 설계를 진행했다면 Card의 필드로 Rank와 Suit을 두는 것을 바로 생각하지는 못 했을 것.)
-
Rank를 먼저 테스트하자. Rank는 Card의 숫자를 나타내는 클래스로 enum 클래스로 만들 것이다.
-
이렇게 Card의 숫자를 나타내는 Rank 클래스를 도메인 규칙에 맞게 생성했다. 누군가가 J가 11을 반환하도록 코드를 수정해도 테스트에서 잡아낼 수 있게 되었다.
-
+) view에서 각 Rank를 숫자로 표현해야 하는 요구사항을 발견했다. 각 Rank마다 어울리는 format을 반환하도록 필드를 추가하자. (이것은 view를 위한 필드이므로 테스트 코드를 작성하지 않아도 된다고 판단했다. TDD는 로직을 테스트하는 것이지, 값 자체를 테스트하는 것이 아니기 때문)

-
다음으로 Suit을 생성하자.
-
다음으로 Rank와 Suit을 필드로 가지는 Card를 생성하자.
- 테스트를 짜기에 앞서, Card의 도메인 로직이나 규칙이 존재하는지 고민하자.
- 고민한 결과, 아직 Card의 도메인 로직이 떠오르지 않는다.
- 도메인 규칙은 Rank와 Suit에서 적용해서 Card에서 따로 적용할 건 없어보이지만, 한 가지 테스트를 해야 한다.
- 동등성 테스트이다. 기본적으로 Card는 식별자가 존재하지 않고, Rank와 Suit을 기준으로 식별하기 때문에 Rank와 Suit이 같다면 같은 Card로 봐야 한다.
- 또한 Card는 Rank와 Suit을 파라미터로 받아 생성하도록 할 예정이다.
- 따라서 두 가지의 테스트 케이스를 짤 수 있다.
- Card는 Rank와 Suit으로 생성할 수 있다.
- Card는 Rank와 Suit이 같다면 같은 객체이다.
- 이제 첫 번째 테스트 케이스부터 짜자.
- CardTest라는 이름의 테스트 클래스를 생성하고 Card 정상 생성 테스트 코드를 짰다.

- Card 클래스가 존재하지 않아 컴파일 에러가 발생하므로 Card 클래스를 생성하자.(필드인 Rank와 Suit도 한 번에 만들어줬다.)

- 테스트 실행 -> 성공!

- 이제 두 번째 테스트 케이스를 짜자.

- 테스트 실행 -> 두 객체가 달라 테스트 실패
- Card 클래스에서 equals&hashcode를 오버라이딩하지 않아 필드가 같은 두 객체를 같다고 보지 않는다.
- Card 클래스 내에 equals&hashcode를 오버라이딩하자.

- 테스트 재시도 -> 성공!

-
이제 Card도 만들었으니, 모든 카드들을 가지고 있는 객체가 필요하다. 이 객체의 이름은 Deck으로 하자.(블랙잭에서 덱은 카드 한 더미를 의미하며, 조커를 제외한 52장의 카드로 구성되어 있음)
-
이 Deck의 역할을 생각해보자.
- Deck 초기화(52장의 Card 객체들을 생성하여 가지고 있어야 한다.)
- Card 셔플(52장의 Card 객체들을 순서대로 가지고 있는 것이 아니라 섞어야 한다.)
- Card 드로우(플레이어와 딜러에게 카드를 한 장씩 나눠줘야 한다.)
- Deck에 Card가 없는데 드로우할 경우 예외 처리
-
첫 번째 역할부터 테스트 코드를 짜자.
- Deck은 처음 생성될 때 52장의 카들르 생성하여 가지고 있어야 한다.




















































