Ruth wins
라고 입력하면 그 선수의 승리가 기록되기만 하면 된다. 궁극적으로는 이를 사용해 사용자들이 포커를 칠 수 있도록 돕는 프로그램을 만드는 것이다.main.go
라는 파일이 있는 애플리케이션이 있다. 이번 챕터에서 다룰 내용을 위해서 만들었던 HTTP 서버 자체에는 관심이 없지만 이 서버가 추상화한 PlayerStore
에는 관심이 있다.PlayerStore
인터페이스로 구현한 FileSystemPlayerStore
를 만들었다. 이 중 일부를 새로 만들 애플리케이션에서 재사용할 수 있어야 한다.$GOPATH/src/github.com/your-name/my-app
package main
안에 main
함수가 있어야 한다. 지금까지 우리의 모든 도메인 코드는 package main
안에 있었고 func main
은 모든 것을 참조할 수 있었다.cmd
폴더와 그 안에 webserver
폴더를 같이 만들어라 (예시: mkdir -p cmd/webserver
).main.go
파일을 이동시켜라.tree
가 설치되어 있다면 돌렸을 때 아래와 같은 폴더 구조를 가져야 한다.main
이어야만 하는 것을 기억하자.poker
패키지 안에 있도록 바꾸자.main.go
에서 불러와서 그 패키지를 사용해서 웹 서버를 만들 수 있다. 그 때 라이브러리 코드는 poker.FunctionName
과 같이 사용할 수 있다go get
을 실행시키기만 하면 된다.go test
를 실행시켜서 아직도 모든 테스트가 통과하는지 확인하자.cmd/webserver
로 가서 go run main.go
를 실행시키자.http://localhost:5000/league
로 들어가서 아직도 작동하는 지 확인하자.cmd
폴더 안에 cli
라는 새로운 폴더를 만들고 그 안에 아래와 같이 main.go
파일을 추가하자.{PlayerName} wins
를 입력할 때 승리를 기록하는 것이다.Play
할 수 있게 해주는 CLI
라는 것을 만들 필요가 있다는 것을 안다. 그것은 사용자가 입력한 값을 읽고 PlayerStore
에 승리를 기록해야 한다.PlayerStore
와 통합이 되는지를 체크하는 테스트를 작성해보자.CLI_test.go
안을 보면 (cmd
폴더 안이 아닌 프로젝트 루트 폴더)StubPlayerStore
을 사용할 수 있다.CLI
타입에 의존 변수를 제공한다.PlayPoker
메소드를 호출한다.CLI
구조체와 메소드를 추가할만큼 충분히 편안해야 한다.Stdin
(유저로부터 들어오는 입력값)을 읽는 것을 시뮬레이션하기 위해서 우리는 특정 선수들의 승리를 기록할 수 있어야 한다.os.stdin
은 main
에서 사용자의 입력값을 가져오기 위해서 사용할 패키지다. 속에 들여다보면 *File
인데 이는 우리가 알고 있듯이 입력값을 받아오는 편리한 방법으로 io.Reader
를 구현한다는 뜻이다.strings.NewReader
를 사용해서 테스트 안에 io.Reader
를 만든다../CLI_test.go:12:32: too many values in struct initializer
CLI
안에 새로운 의존 변수들을 넣어야 한다.server_test.go
에서 우리는 승리가 기록되는지를 체크하는 코드를 이미 작성했다. 이 코드를 helper로 만들어서 반복을 줄이자.server_test.go
와 CLI_test.go
에 있는 코드를 대체하면 테스트는 아래와 같아야 한다.Package bufio는 버퍼가 있는 I/O를 구현한다. 이것은 인터페이스를 구현하는 다른 객체(Reader 혹은 Writer)를 만들면서 io.Reader나 io.Writer 객체를 감싸고 버퍼와 텍스트 I/O를 위한 몇몇 도움을 제공한다.
Scanner.Scan()
새로운 줄이 나올 때까지 읽을 것이다.string
을 리턴하기 위해 Scanner.Text()
를 사용할 수 있다.main
에 작성해야 한다. 우리는 항상 가능한 빨리 완전히 작동가능한 소프트웨어를 만드는 것을 갈망해야하는 것을 기억하자.main.go
파일 안에 아래와 같이 입력하고 실행시키자. (의존성을 해결하기 위해 당신 컴퓨터에 맞춰서 주소를 변경해야 할 수도 있다.)playerStore
필드들과 CLI
안에 in
을 값을 대입하려고 했기 때문에 생겨난 일이다. 그것들은 내보내지지 않은 (unexported), private 필드들이다. 테스트 코드들은 CLI
(poker
)와 같은 패키지에 있었기 때문에 이렇게 할 수 있었다. 하지만 main
은 main
패키지에 있기 때문에 접근 권한이 없다.CLI
의 의존 변수들을 private으로 올바르게 만들었다 (왜냐하면 CLI
를 사용하는 사용자들에게 이 변수들을 보여주고 싶지 않기 때문이다). 하지만 사용자들이 이것을 만들 방법을 아직 제공하지 않았다.package mypackage_test
main
처럼 우리가 접근이 가능한 내보내진 (exported) 타입들에만 테스트가 가능하다면 어떨까요?_test
를 붙일 것을 강력하게 추천한다. 이렇게 한다면, 당신은 당신의 패키지에 public 타입들에만 접근이 가능해 질 것이다. 이는 public API들만 테스트한다는 규칙을 강제하는데 큰 도움이 된다. 당신이 아직도 패키지 내부에 있는 것을 테스트하고 싶다면, 테스트하고 싶은 패키지에 따로 테스트를 만들 수 있다.package foo_test
를 사용함으로써 마치 당신이 당신의 패키지를 사용하는 사람들처럼 불러와서 당신의 코드를 테스트하게끔 강요하게 해 도움을 줄 것이다.main
을 고치기 전에 CLI_test.go
의 테스트들의 패키지를 poker_test
로 변경하자.CLI_test
에서 더이상 사용할 수 없는 내보내지지 않은 stub (테스트를 위해 작성한 임시 코드)과 helper 함수들을 가지게 되었다. 왜냐하면 이 helper들은 poker
패키지안에 _test.go
파일에 정의되어 있기 때문이다.poker
패키지를 사용하는 개발자들이 그들의 코드에서 작동하기를 희망하는 PlayerStore
stub을 만들지 않게 하는 것을 의미한다.testing.go
라는 파일을 만들고 그 안에 stub과 helper들을 만들어보자.CLI
테스트에서 그 코드를 불러와야 한다.main
에서 가지고 있던 문제들이 똑같이 있다는 걸 볼 수 있다.CLI
도 바꿔야 하는데 그렇게 하면 reader대신에 bufio.Scanner
를 생성할 때 자동으로 감싸지면서 가질 수 있게 된다.main.go
파일로 가서 우리가 방금 만든 생성자를 사용해야 한다.file_system_store
를 만드는 각각의 애플리케이션에 반복되는 코드들이 좀 있다. 이것은 우리의 패키지 디자인의 약간의 문제가 있다고 느껴지게 하기 때문에 주소를 불러들여 파일을 열고 PlayerStore
를 리턴하는 식으로 중복된 코드들을 하나의 함수로 만들어야 한다.FileSystemPlayerStoreFromFile
이 파일을 닫는 함수를 리턴한다는 것을 알아야 한다. 그렇기 때문에 우리는 store를 다 쓰고 나서 열었던 파일을 닫을 수 있다.main
을 위한 별도의 폴더를 가지게 되었다.mypackage_test
가 어떻게 당신의 코드와 함께 사용할 다른 패키지들과 같은 경험을 제공하는 테스트 환경을 만드는데 도움을 주는지 배웠다. 그리고 이것이 코드가 작동하는지(혹은 작동하지 않는지)와 코드를 통합할 때 생기는 지를 빠르고 쉽게 찾을 수 있는지도 배웠다.io.Reader
를 이용해서 os.Stdin
에서 입력값을 읽는 것이 얼마나 쉬운지 보여줬다. 그리고 사용자의 입력값을 각각의 줄로 나눠서 쉽게 읽기 위해서 bufio.Scanner
를 사용했다.PlayerStore
를 새로운 애플리케이션에서 사용하는데 거의 노력이 들지 않았다 (패키지를 한 번 바꿨을 뿐이다). stub 코드를 public으로 하기로 결정했기 때문에 결국 테스트 또한 매우 쉬웠다.