우아한테크코스 6기 백엔드 프리코스 - 1주차 미션

TODO list

지금까지 통과 한 테스트는 취소선으로 표시했다.

m1t01 - 1부터 9까지의 숫자 중 서로 다른 세 자리 숫자를 생성할 수 있어야 한다.
m1t02 - 서로 다른 세 자리 수가 아닌 사용자의 입력에 대해서는 IllegalArgumentException을 발생시킨다.
m1t03 - IllegalArgumentException이 발생하면 애플리케이션이 종료되어야 한다.
m1t04 - n개의 같은 수가 같은 자리에 있는 경우 n개의 스트라이크를 결과로 얻을수 있어야 한다. (n <= 3)
m1t05 - n개의 같은 수가 다른 자리에 있는 경우 n개의 볼을 결과로 얻을수 있어야 한다. (n <= 3)
m1t06 - 같은 수가 0개인 경우 낫싱이라는 결과를 얻을수 있어야 한다.
m1t07 - 사용자의 유효한 입력에 대한 적절한 결과를 출력할 수 있어야 한다.
m1t08 - 3스트라이크인 경우 게임이 종료된다.
m1t09 - 게임이 종료된 뒤 1을 입력받으면 새로운 게임이 진행된다.
m1t10- 게임이 종료된 뒤 2를 입력받으면 애플리케이션이 종료된다.
m1t11 - m1t01을 연속해서 여러 번 실행해도 유효한 세 개의 숫자를 생성해야 한다.

m1t06

낫싱이라는 결과는 볼이 0개, 스트라이크가 0개일 때 발생한다. m1t04, m1t05 테스트에서 이미 스트라이크와 볼 판정이 정확하다는 결과를 얻었다. 결국 낫싱은 자연스럽게 테스트된 것이라고 판단해서 일단 넘어가기로 했다.

m1t02

회원의 입력을 받아 BaseBallNumber 인스턴스를 생성하는 과정에서 IllegalArgumentException이 발생함을 테스트한다. (UserInputHandler의 생성자에 GameRule 객체가 빠졌다.)

m1t02

테스트가 통과하도록 빠르게 구현했다. 이전의 비싼 리팩토링으로 여러 개의 객체에 책임을 분산했기 때문에 쉽게 구현할 수 있었다.

UserInputHandler

이 클래스는 사용자의 입력을 연산이 가능한 BaseBallNumber 인스턴스로 만들어준다. 검증에 대한 책임은 BaseBallNumber에 있다.

살짝 졸면서 작성한 테스트를 다시 다듬었다.

m1t02-v2

m1t03

이 테스트에 필요한 객체는 GameRound이다. 1라운드의 게임을 추상화 한 클래스이다. 입력된 값에 대한 적절한 값을 출력한다.

m1t03

stdin으로부터 잘못된 입력을 받은 경우 GameRound 객체는 InvalidNumberException 예외를 던진다.

m1t03-v2

테스트 코드에 오류가 있어서 수정했다.

GameRound-impl1

리듬 한 사이클의 보폭을 줄이기 위해 멀리 보지 않고 테스트를 통과시키는 것만 생각했다.

m1t07

정상적인 입력에 대해 적절한 값을 출력하는지 확인하는 테스트이다.

m1t07

위의 테스트를 작성하기 위해 리다이렉션에 대해 학습하는 테스트를 작성했다.

learn-redirection

m1t07은 한 번에 통과하기에는 부담스러워서 먼저 아래의 작은 테스트를 작성했다.

single-turn

휴… 이번 테스트는 많은 우여곡절이 있었다.

NoSuchElementException

표준 입력 스트림을 내가 지정한 스트림으로 리다이렉션하는 코드가 포함된 테스트에서 NoSuchElementException이 발생했다.
이 예외는 Scanner가 더 이상 입력받을 값이 없을 때 발생한다.
System.setIn메서드로 표준 입력 스트림을 바꾸지만 그 전에 생성된 Scanner 객체는 생성될 때의 스트림을지속적으로 참조한다.
미션의 라이브러리 속의 Console 코드를 보면 최초로 readLine 메서드가 호출될때 Scanner 인스턴스를 싱글톤으로 생성한다.

scanner

아래는 m1t07을 통과시키기 위해 코드를 작성하다가 깨진 테스트 중 하나인 m1t03을 수정한 것이다.

m1t03-v3

최종적으로 완성한 테스트는 다음과 같다.

test-for-one-guess

guess-until-correct

before-after-each

이 테스트를 통과시키기 위해 작성한 GameRound 클래스는 게임의 한 라운드를 진행한다. 한 라운드는 3스트라이크가 나올때까지 계속 진행된다.
이 클래스의 역할은 입력에 대한 결과를(3스트라이크일때까지) 출력하는 것이다.

GameRound-1 GameRound-2

m1t08

m1t07 테스트를 수정 보완하다 보니 m1t08 테스트까지 포함하게 되었다.

m1t09 m1t10

해당 테스트는 미션과 함께 제공된 테스트를 활용했다.

이 테스트를 통과하기 위해 Application을 아래와 같이 구현했다.

application-1 application-2

2일차 마무리

TDD책을 84페이지까지 읽고 흉내 내보면서 애플리케이션을 완성했다. 중간에 새로운 클래스를 도입하거나 새로운 메서드를 사용하여 기존의 구현과 테스트가 깨지면서 시간이 오래 걸리는 테스트도 있었다. 테스트를 작성하고, 통과하기만을 위한 구현을 반복했는데(애플리케이션 전체에 대한 생각은 전혀 하지 않았다) 진짜 모든 요구사항을 만족하는 애플리케이션이 완성되었다.

elapsedtime

커피를 안 마시고 차를 마셨더니 잠이 쏟아져서 꽤 오래 결렸다. 😅
내일부터는 코드를 깨끗하게 정리하는 리팩토링이다.

reference

Comments