볼링게임 TDD[3] 을 끝으로 볼링게임 TDD를 마무리하려고 한다.
우선 남은 할 일 목록을 정리해보자.
[] 볼링 점수 계산기를 만든다. (스트라이크, 스페어를 고려한다.)
[] 투구(pitch) 후 쓰러진 pin은 BowlingScore에 전달되어야 한다.
[] 볼링을 상속받는 객체로는 볼링 플레이어와 볼링 점수 계산기가 존재한다.
(플레이어와 점수 계산기는 1 : 1 관계를 갖는다.)
[] 점수 계산기를 통해 계산된 점수는 점수 표출기를 통해 점수를 볼 수 있어야 한다.
잘 못된 할 일 목록과 불 필요한 목록은 정리하고 볼링게임을 완성하기 위한 할 일 만 남겨두도록 하겠다.
[] 스트라이크, 스페어등 볼링 룰을 적용한다.
[] 점수 계산기를 통해 최종 점수를 계산해야 한다.
[] 최종 점수는 점수 표출기를 통해 보여야 한다.
[] 투구(pitch) 후 쓰러진 pin은 BowlingScore에 전달되어야 한다.
[v] 투구(pitch) 후 쓰러진 pin은 BowlingScore에 전달되어야 한다.
[v] 스트라이크, 스페어등 볼링 룰을 적용한다.
[v] 점수 계산기를 통해 최종 점수를 계산해야 한다.
@Test
void 넘어진_핀_테스트(){
BowlingPlayer player1 = new BowlingPlayer("player1");
while(player1.getPitchCount() > 0){
player1.pitch();
}
System.out.println(player1.getDownPins());
}
@Test
void 점수계산기_테스트(){
BowlingPlayer player1 = new BowlingPlayer("player1");
while(player1.getPitchCount() > 0){
player1.pitch();
}
System.out.println(player1.toString());
}
public class BowlingPlayer extends Bowling{
private String name;
private List<Integer> scores;
public BowlingPlayer(String name) {
this.name = name;
scores = new ArrayList<>();
}
public String getName() {
return name;
}
public List<Integer> getScores() {
scoreCalculator(getDownPins());
return scores;
}
public void pitch() {
setPitchCount();
}
public void scoreCalculator(List<Integer> downPins){
int countByFrame = 0;
int scoreByFrame = 0;
int leftScore = 0;
int rightScore = 0;
for(int i = 0, n = downPins.size(); i < n; i++){
countByFrame++;
if(downPins.get(i) != -1){ // 이전 투구가 스트라이크인지 확인
scoreByFrame += downPins.get(i);
}
if(countByFrame == 1 && scoreByFrame == 10){ // 스트라이크 체크
if((i+3) < downPins.size() -1){ // 마지막 투구 체크
leftScore = downPins.get(i+2);
rightScore = downPins.get(i+3) == -1 ? 10 : downPins.get(i+3);
scoreByFrame += leftScore + rightScore;
}
scores.add(scoreByFrame);
countByFrame = 0;
scoreByFrame = 0;
i++;
}
else if(countByFrame == 2){
if(scoreByFrame == 10 && (i+1) != downPins.size() -1){ // 마지막 투구가 아니고 스페어면
leftScore = downPins.get(i+1);
scoreByFrame += leftScore;
}
scores.add(scoreByFrame);
countByFrame = 0;
scoreByFrame = 0;
}
}
scores.add(downPins.get(20));
}
@Override
public String toString() {
return "선수 이름 : " + "'" + name + '\''
+ " 투구 당 쓰러트린 핀{" + getDownPins() + '}'
+ " 점수 = " +
getScores().stream().mapToInt(Integer::intValue).sum() + '}';
}
}
점수 계산기 테스트를 하며 여러 번 빨간 막대를 보았다. 연속된 빨간 막대 덕분에 과연 이걸 끝낼 수 있을까 의심되었지만
빨간 막대 덕분에 코드의 잘못된 부분을 알게 되었고, 스트라이크와 스페어 룰을 적용하여 점수를 계산할 수 있었다.
또한 단위 테스트를 통해 API를 검증하였다. (jUnit을 java API 사용법 테스트로 중간중간 활용하였다.)
단위 테스트는 Java의 기본 API가 될 수도 있고, 내가 만든 기능이 될수도 있다.
@Test
void 존재하지않는_인덱스일땐(){
List<Integer> testList = new ArrayList<>();
IndexOutOfBoundsException e
= assertThrows(IndexOutOfBoundsException.class, () ->{
testList.remove(20);
});
assertThat(e.getMessage()).isEqualTo("Index: 20, Size: 0");
}
나의 경우에는 downPins라는 컬렉션의 사이즈를 지정하지 않아 점수를 계산할 때 OutIndexOutOfBoundsException가 발생했고,
그것을 해결하기 위해 볼링 객체에 생성자에 기본 사이즈를 지정해주었다.
public Bowling(){
this.pin = 10;
this.pitchCount = 21;
this.frame = 1;
this.downPins = new ArrayList<>(21);
}
점수 계산기를 통해 계산된 최종 점수는 아래 볼링 스코어 계산기 사이트를 통해 여러 번 검증하였다.
검증 도중에도 잘못된 최종 점수가 나와서 계속 수정을 하였다....
이제 점수 표출기를 통해 정말 볼링 점수 모니터를 통해 보는 것처럼 만들어보자!
처음 할 일 목록을 만들며 생각한 볼링게임 설계 단계에서는
[] 볼링의 하위 객체로는 볼링 플레이어와 볼링 점수 계산기가 존재한다. (플레이어와 점수 계산기는 1 : 1 관계를 갖는다.)
위와 같이 생각하였지만 지금 와서 다시 생각해보니 볼링 플레이어는 볼링을 상속받고 있고, 볼링 플레이어는 scores라는
멤버 필드를 가져서 이것을 점수 표출기에 넘겨주면 그것을 볼링 점수 모니터처럼 콘솔에 뿌려주도록 할 것이다.
@Test
void 점수는_어떻게_쌓이고있나(){
BowlingPlayer player1 = new BowlingPlayer("player1");
while(player1.getPitchCount() > 0){
player1.pitch();
}
System.out.println(player1.getScores());
}
console
[7, 4, 9, 9, 8, 9, 18, 12, 7, 7, 0]
[5, 9, 9, 6, 20, 20, 19, 9, 13, 9, 0]
[19, 19, 20, 19, 9, 13, 3, 13, 4, 10, 2]
우선 다시 한번 단위 테스트를 진행하였다. scores에는 최종 점수를 계산하기 위해 프레임 별 계산된 점수를 저장해둔 List <Integer>
멤버 변수이고 총 11번의 점수가 쌓이는 것을 확인하였다. 마지막 11번째의 인덱스는 마지막 21번째 투구이다.
음.. 앞에 점수를 계속해서 더해주며 점수를 보여주면 점수 표출기를 손쉽게 만들 수 있을 것 같다.
@Test
void 점수계산기_테스트(){
BowlingPlayer player1 = new BowlingPlayer("player1");
BowlingPlayer player2 = new BowlingPlayer("player2");
while(player1.getPitchCount() > 0){
player1.pitch();
}
System.out.println(player1.toString());
player1.printScore();
System.out.println();
System.out.println();
player2.pitch();
player2.pitch();
player2.pitch();
player2.pitch();
player2.pitch();
System.out.println(player2.toString());
player2.printScore();
}
package bowling;
public interface PrintScore {
void printScore();
}
@Override
public void printScore() {
int sum = 0;
StringBuilder print = new StringBuilder("");
int size = this.scores.size() == 11 ? 10 : this.scores.size();
for (int i = 0; i < size; i++) {
sum += this.scores.get(i);
if(i == 9){
sum += scores.get(i+1);
}
print.append(" | ").append(i + 1).append("Frame : ").append(sum).append(" | ");
}
System.out.println("--------------------------------------------------------------------------------------------------------------------------");
System.out.println(print.toString());
System.out.println("--------------------------------------------------------------------------------------------------------------------------");
}
볼링게임 TDD를 진행하며 느낀 점
- 아직 객체지향에 대한 이해가 부족하다.
- 좀 더 작은 설계를 위한 능력이 부족하다.
- 기획이 어렵다는 걸 알았다.
- TDD 덕에 나아갈 수 있었다.
- TDD에 대한 이해가 부족하다.
볼링게임 TDD는 여기서 마무리하겠습니다.
코드는 github.com/m3252github.com/m3252/study/tree/master/tdd/src/main/java/bowling 에 오시면 보실 수 있으며
코드는 앞으로 좀 더 수정할 예정이지만 블로그는 연재는 여기까지입니다. 감사합니다
'공부 > TDD' 카테고리의 다른 글
볼링게임 TDD [2] (0) | 2020.10.02 |
---|---|
볼링게임 TDD [1] (0) | 2020.09.30 |
[OKKYCON: 2018] 이규원 - 당신들의 TDD가 실패하는 이유 (0) | 2020.09.26 |
[OKKYCON: 2018] 자바지기(박재성)- TDD 의식적으로 연습하기 (0) | 2020.09.20 |
테스트 주도 개발 [10 - 17장] (0) | 2020.09.12 |
댓글