Interacting with User Input

Sometimes a command-line application needs to ask the user a question. Aruba supports this, allowing you to write scenarios that include a user responding to requests for information from the command-line application. We’ve been getting feedback from user testing of our calculator that a significant number of our users want to be able to perform additions without saving them to a file first. Let’s write another scenario to describe that use case:

 Scenario​: Add two numbers interactively
  When the calculator is run with no input
  And I enter the calculation ​"2+2"
  Then the output should be ​"4"

Run cucumber to generate the new step definition snippets, and then paste them into features/step_definitions/calculator_steps.rb:

 When(​/^the calculator is run with no input$/​) ​do
  pending ​# Write code here that turns the phrase above into concrete actions
 end
 
 When(​/^I enter the calculation "([^"]*)"$/​) ​do​ |arg1|
  pending ​# Write code here that turns the phrase above into concrete actions
 end

We’ll implement the first step definition by delegating to a variation of the Aruba step definition we used earlier. This time, we’ll tell Aruba we’re going to interact with the child process:

 When(​/^the calculator is run with no input$/​) ​do
  steps ​%{
  When I run `calculator` interactively
  }
 end
 
 When(​/^I enter the calculation "([^"]*)"$/​) ​do​ |calculation|
  steps ​%{
  When I type "#{calculation}"
  }
 end

We’ve used two new Aruba step definitions here. You can probably guess how they work, but let’s explain them:

 /^I run `([^`]*)` interactively$/

Executes the command between the backticks in a child process and connects to the STDIN, STDOUT, and STDERR streams, ready for subsequent steps to interact with the child process.

 /^I type "([^"]*)"$/

Sends the given text to the running process’ STDIN stream.

Run cucumber, and you should have a failing test. We can see there’s an error here, because our calculator isn’t executing successfully, but we aren’t able to see what the problem is. We can use @announce-output again to see the output. This time we’ll just add it to our new scenario.

 @announce-output
 Scenario​: Add two numbers interactively
  When the calculator is run with no input
  And I enter the calculation ​"2+2"
  Then the output should be ​"4"

Run cucumber, and you should see the error, and the output from the calculator command:

 Feature: Adding
 
  Scenario: Add two numbers
  Given the input "2+2"
  When the calculator is run
  Then the output should be "4"
 
  @announce-output
  Scenario: Add two numbers interactively
  When the calculator is run with no input
  And I enter the calculation "2+2"
 <<-STDOUT
 
 STDOUT
 <<-STDERR
 ~/command_line_applications/11/bin/calculator:2:in `read':
  no implicit conversion of nil into String (TypeError)
  from ~/command_line_applications/11/bin/calculator:2:in `<main>'
 
 STDERR
 <<-STDOUT
 
 STDOUT
 <<-STDERR
 ~/command_line_applications/11/bin/calculator:2:in `read':
  no implicit conversion of nil into String (TypeError)
  from ~/command_line_applications/11/bin/calculator:2:in `<main>'
 
 STDERR
  Then the output should be "4"
  expected "calculator" to be successfully executed
  (RSpec::Expectations::ExpectationNotMetError)
  ./features/step_definitions/calculator_steps.rb:18
  features/adding.feature:13
 <<-STDOUT
 
 STDOUT
 <<-STDERR
 ~/command_line_applications/11/bin/calculator:2:in `read':
  no implicit conversion of nil into String (TypeError)
  from ~/command_line_applications/11/bin/calculator:2:in `<main>'
 
 STDERR
 <<-STDOUT
 
 STDOUT
 <<-STDERR
 ~/command_line_applications/11/bin/calculator:2:in `read':
  no implicit conversion of nil into String (TypeError)
  from ~/command_line_applications/11/bin/calculator:2:in `<main>'
 
 STDERR
 
 Failing Scenarios:
 cucumber features/adding.feature:10
 
 2 scenarios (1 failed, 1 passed)
 6 steps (1 failed, 5 passed)
 0m0.890s

We’ve had an error from line 2 of our calculator program, where we try to read the contents of the input file passed as a command-line argument. That’s because we haven’t changed our application to wait for user input yet, so it’s still expecting to be told what file to read. We need to change our calculator program to ask for input if no file is specified:

 #!/usr/bin/env ruby
 input = if ARGV.any?
  File.read(ARGV[0])
 else
  puts "Please enter the calculation you'd like me to perform"
  gets
 end
 
 numbers_to_add = input.split('+').map { |n| n.to_i }
 
 total = 0
 numbers_to_add.each do |number|
  total += number
 end
 
 print(total)

Now if there are no command-line arguments, our calculator will ask the user to enter the calculation and then sit and wait for them to type something. Remove the @announce-output tag from the scenario, and let’s see how this plays out when we run our scenario:

 Feature: Adding
 
  Scenario: Add two numbers
  Given the input "2+2"
  When the calculator is run
  Then the output should be "4"
 
  Scenario: Add two numbers interactively
  When the calculator is run with no input
  And I enter the calculation "2+2"
  Then the output should be "4"
 
 2 scenarios (2 passed)
 6 steps (6 passed)
 0m0.654s

Excellent! We’ve modified the calculator, and not only is our new scenario passing, but so is the first one, which means we haven’t broken the existing behavior. Let’s make one last change and refactor our step definitions to make them even cleaner. Instead of delegating to Aruba’s step definitions, let’s use the Aruba API directly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.103.96