Ruth wins. The intention is to eventually be a tool for helping users play poker.
main.gofile that launches an HTTP server. The HTTP server won't be interesting to us for this exercise but the abstraction it uses will. It depends on a
FileSystemPlayerStorewhich implements that interface. We should be able to re-use some of this for our new application.
mainfunction inside a
package main. So far all of our "domain" code has lived inside
package mainand our
func maincan reference everything.
cmddirectory with a
webserverdirectory inside that (e.g
mkdir -p cmd/webserver).
treeinstalled you should run it and your structure should look like this
main.goso we can use it to create our web server. Then we can use our library code by using
go testand check they're still passing
go run main.go
http://localhost:5000/leagueand you should see it's still working
cli(command line interface) and add a
main.gowith the following
CLIwhich will allow us to
Playpoker. It'll need to read user input and then record wins to a
PlayerStorehow we'd like.
CLI_test.go(in the root of the project, not inside
StubPlayerStorefrom other tests
CLIstruct with the respective field for our dependency and add a method.
Stdin(the input from the user) so that we can record wins for specific players.
os.Stdinis what we'll use in
mainto capture the user's input. It is a
*Fileunder the hood which means it implements
io.Readerwhich as we know by now is a handy way of capturing text.
io.Readerin our test using the handy
strings.NewReader, filling it with what we expect the user to type.
./CLI_test.go:12:32: too many values in struct initializer
server_testwe earlier did checks to see if wins are recorded as we have here. Let's DRY that assertion up into a helper
Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.
Scanner.Scan()will read up to a newline.
Scanner.Text()to return the
stringthe scanner read to.
main. Remember we should always strive to have fully-integrated working software as quickly as we can.
main.goadd the following and run it. (you may have to adjust the path of the second dependency to match what's on your computer)
CLI. These are unexported (private) fields. We could do this in our test code because our test is in the same package as
poker). But our
mainis in package
mainso it does not have access.
CLIprivate (because we don't want them exposed to users of
CLIs) but haven't made a way for users to construct it.
_testat the end. When you do this you will only be able to have access to the public types in your package. This would help with this specific case but also helps enforce the discipline of only testing public APIs. If you still wish to test internals you can make a separate test with the package you want to test.
package foo_testwill help with this by forcing you to test your code as if you are importing it like users of your package will.
mainlet's change the package of our test inside
CLI_testbecause the helpers are defined in the
_test.gofiles in the
pokerpackage won't have to create their own stub
PlayerStoreif they wish to work with our code.
testing.goand add our stub and our helpers.
CLItest you'll need to call the code as if you were using it within a different package.
CLIso it stores a
bufio.Scannerinstead of the reader as it's now automatically wrapped at construction time.
main.goand use the constructor we just made
file_system_storefrom its contents. This feels like a slight weakness in our package's design so we should make a function in it to encapsulate opening a file from a path and returning you the
FileSystemPlayerStoreFromFilereturns a closing function, so we can close the underlying file once we are done using the Store.
mypackage_testhelps us create a testing environment which is the same experience for other packages integrating with your code, to help you catch integration problems and see how easy (or not!) your code is to work with.
os.Stdinis very easy for us to work with as it implements
io.Reader. We used
bufio.Scannerto easily read line by line user input.
PlayerStoreinto our new application (once we had made the package adjustments) and subsequently testing was very easy too because we decided to expose our stub version too.