Thomas Countz

Testing Ruby’s `gets` & `puts`

The Problem.

You want to TDD some behavior that interacts with the command line:

puts "Would you like to continue? [yN]"
answer = gets.chomp.downcase

But testing this idea is difficult; when your tests run these lines of code, they can cause your tests to hang or send unwanted output to your console.

A Solution.

An Example Test.

RSpec.describe ConsoleInterface do

  describe '#ask_question' do
    it 'sends a prompt question to output' do
      output =
      console_interface = output)


      expect(output.string).to include("continue?")

  describe '#answer' do
    it 'returns a formatted string received from input' do
      input ="iNPut\n")
      console_interface = input)

      expect(console_interface.answer).to eq("input")


An Example Implementation.

class ConsoleInterface

  def initialize(input: $stdin, output: $stdout)
    @input = input
    @output = output

  def ask_question
    @output.puts "Would you like to continue? [yN]"

  def answer


Why I Like This.

The power of Ruby is that if it quacks like a duck, it must be a duck! By combining this freedom with dependency injection, we can quickly grab control over our dependency on what we often take for granted: the command line.

Also, you might be excited to learn that you’ve just used a test double! They can often be seen as big scary controversial things that require you to pull in heavy libraries, but because of duck-typing, using a test-double can be as simple as injecting a built-in object that we have more control over.

· ruby, testing