- Deal with external dependencies/frameworks
- Use lessons learned to write a larger program
In this exercise, we will write a traditional TDD exercise application: Conway's Game of Life. This game has a few simple rules that simulate "life."
To help you build this game, this exercise comes with a basic framework that handles some of the lower level display logic.
There is a Terminal
class that you can use to print content to the screen. It is used like this (you don't need to test
this out):
var terminal = Terminal.instance();
terminal.setContent("text to show")
You can press "q" to quit the program.
A skeleton game engine has also been written for you. Use it like this:
var engine = new Engine();
engine.pipe(printer: IPrintable);
engine.game(game: IGame);
engine.start();
The IGame
instance has a cycle
method that is called every engine.getRefreshRate()
milliseconds (default: 250). In
that method, use the IPrintable
argument's print
method to push contents to the screen.
- Make sure you stub or mock the
Terminal
in your game tests. TheTerminal
represents an external dependency which you never want to call in your tests. - Write your tests WITH your code; not necessarily beforehand, but definitely don't wait until the end
- If something is difficult to test, re-think what you've written. Inversion of control is usually a good place to start.
- Mocking/stubbing/spying-on instance methods called during a constructor is sometimes challenging, since it will impact
all subsequent instances unless you are careful. If you plan to do this, use this syntax (
sandbox
ensures your hooks get cleaned up):
var mySpy = sandbox.spy(TheClassName.prototype, 'instanceMethod');
Conway's Game of Life is a simple game with four rules:
- Any live cell with fewer than two live neighbours dies, as if caused by under-population.
- Any live cell with two or three live neighbours lives on to the next generation.
- Any live cell with more than three live neighbours dies, as if by overcrowding.
- Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
Build this game with a board size of your choosing. You can use spaces for empty cells and any other character for
living ones (for example, this one: █). You may need to create more files and classes to do this elegantly. The
grunt watch
process will detect these new files without problem.
To run your game, initialize your game logic in run.ts. There is already a example in that file. To run it:
$ npm run e4
You can press "q" to quit the program.
The current sample code in run.ts
is using a simple object that matches the IGame
interface. Because
run.ts
is not covered by tests, it is important that it is as small as possible. Try refactoring your version of
this code to use a more elegant design. For example, using a class to wrap the game logic better:
var engine = new Engine();
engine.pipe(Terminal.instance());
engine.game(new MineSweeper());
engine.start();
or the Facade Pattern to hide this initialization logic:
new MineSweeperGame().start();
You may want to make these types of changes last after you have things working.