Example of top-down style (London school) TDD
Implement a simple Tic Tac Toe game
Controls game.
- start a game
- while the game is not over, ask user inputs and update the board
- when game is over, show a message.
This component uses all other components
functionalities:
- ask player names
- ask user inputs (set mark to arbitrary position)
- check if the game is over
- show board
functionalities:
- register user input (mark and position)
- check if game is over
- get a winner ("o", "x", or "" when there is not winner)
functionalities:
- register player (accepts player name)
- get current player
- alternate current player when turn switches
- get player by mark ("o" or "x")
functionalities:
- shows message (in the console, in this implementation)
functionalities:
- ask user input (from the console, in this implementation)
Starting from the highest level of the components (main.go
in this case), you test interactions between components by using mocks. Unlike traditional TDD, where you have a red
- green
- refactor
cycle, you have red
- red
- ... - red
- green cycle.
For example of main.go
,
// if game is over, show message
gameMock := mocks.NewMockGame(mockCtrl)
gameMock.EXPECT().InitGame()
gameMock.EXPECT().IsOver().Return(true)
gameMock.EXPECT().ShowResultMessage()
subject(gameMock)
You write a test above first, then implement Game
.
- (red) you get an error something like mocks is not defined
- (red) you create a mock for
Game
- (red) you get an error like
IsOver
method is not implemented - (red) you create a method
IsOver
in the mock - ...repeat...
- (red) you create a method
ShowResultMessage
in the mock - (red) now you get an error
InitGame
is not called - (red) you call InitGame in the
main.go
file - (red) you get error like
IsOver
is not called - ...repeat...
- (green) implementation is correctly done
When designing an application, it's natural for me to start from high level since I don't know yet how the lowest level behaves. Top down TDD would match how I design.
run go run ./main.go
run go test ./...