Originally posted at ellehallal.devπ©π½βπ»
This is a quick blog on testing output with RSpec. Currently, I am working on a Tic Tac Toe game in Ruby, where a user can play against a computer.
Previous test attempts
Iβve experienced issues testing a loop in the game, where it keeps requesting moves from players until the board is full or a player has won.
def main_game
play_move until @game.over?
end_of_game
end
One attempt at testing this was to spy on the play_move
and end_of_game
methods. This worked fine if a full board was provided.
However, this was proving difficult to test when an incomplete board was present. Despite simulating user input, the test would hang at this stage. The same issue occurred when using object doubles.
Testing output
One of my mentors suggested testing the output of the end_of_game
method. The end_of_game
method prints the Tic Tac Toe board and the outcome of the game.
it 'plays a game that ends with a winning player' do
expect { controller.main_game }
.to output("""
1 | x | x
----------------
o | o | x
----------------
x | o | o
The current player is x
Choose a position from 1-9:
x | x | x
----------------
o | o | x
----------------
x | o | o
x is the winner!""")
.to_stdout
The multi-lines and alignment was also proving difficult to get right for the expected output. The key element that needed to be tested was the outcome of the game, which was the last line of the output: 'x is the winner!'
StringIO
StringIO is a βstring-based replacement for an IO object. It acts same as a file, but itβs kept in memory as a Stringβ.
The idea is to catch the stream of output and redirect it. To check the last line of the output was correct, my mentor suggested trying the following:
it 'plays a game that ends with a winning player' do
controller = controller_setup([1, 'x', 'x', 4, 'o', 'x', 'x', 8, 'o'])
allow($stdin).to receive(:gets).and_return('8', '4', '1')
$stdout = *StringIO*.new
controller.main_game
output = $stdout.string.split("\n")
expect(output.last).to eq('x is the winner!')
end
In this test:
A new instance of the
controller
class is created, with an incomplete boardThe input is simulated to play the three remaining positions on the board
The standard output
$stdin
is redirected to a new instance ofStringIO
The
main_game
method is called to play and complete the gameThe output is then saved to the variable
output
, converted to a string, and split at the points where there is a new line to create an array of stringsThe last item in the array is expected to be 'x is the winner!'
Iβll continue to use this method when testing large blocks of text with multiple lines. Itβs significantly simpler than trying to align multi-line outputs in a test.
Top comments (0)