rspec - 如何在 ruby 中测试 nil 输入

rspec - how to test for nil input in ruby

我正在尝试编写规范来测试当用户仅按下 "Enter" 键时我的代码将如何反应,即不输入任何数据仅按下 "Enter"。

代码本身会循环,直到输入有效内容,但我无法获取规范来测试它。下面的代码是 class 和规范的示例。

请注意,在规范中,我尝试用 with_input('') 替换 "asks repeatedly" 部分,但它似乎挂起(或循环)

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

  def ask_for_number
    @output.puts "Input an integer 5 or above"
    loop do
      input = @input.gets.to_i
      return true if input >= 5
      @output.puts "Invalid. Try again:"
    end
  end
end

--- 和规范

require 'stringio'
require_relative 'Example' 
describe Example do
  context 'with input greater than 5' do
    it 'asks for input only once' do
      output = ask_for_number_with_input(6)

      expect(output).to eq "Input an integer 5 or above\n"
    end
  end

  context 'with input equal to 5' do
    it 'asks for input only once' do
      output = ask_for_number_with_input('5')

      expect(output).to eq "Input an integer 5 or above\n"
    end
  end

  context 'with input less than 5' do
    it 'asks repeatedly, until a number 5 or greater is provided' do
      output = ask_for_number_with_input(2, 3, 6)

      expect(output).to eq <<~OUTPUT
        Input an integer 5 or above
        Invalid. Try again:
        Invalid. Try again:
      OUTPUT
    end
  end

  def ask_for_number_with_input(*input_numbers)
    input = StringIO.new(input_numbers.join("\n"))
    output = StringIO.new

    example = Example.new(input: input, output: output)
    expect(example.ask_for_number).to be true

    output.string
  end
end

当你将其替换为

output = ask_for_number_with_input("")

它永远循环,因为这就是你的代码告诉它做的,你希望它循环直到它收到一个大于 6 的数字,这永远不会发生,@input.gets.to_i 只会继续返回 0 因为 IO#gets

Returns nil if called at end of file.

要让它停止挂起,只需给它另一个值:

it 'asks repeatedly, until a number 5 or greater is provided' do
  output = ask_for_number_with_input("", "", 6)

  expect(output).to eq <<~OUTPUT
    Input an integer 5 or above
    Invalid. Try again:
    Invalid. Try again:
  OUTPUT
end

现在它通过了

只需模仿循环:

require "spec_helper"

describe 'Example' do
  let(:entered_value) { 6 }
  let(:stdin) { double('stdin', gets: entered_value) }
  let(:stdout) { double('stdout') }
  subject { Example.new(input: stdin, output: stdout) }

  describe '#ask_for_number' do
    before(:each) do
      allow(subject).to receive(:loop).and_yield
    end

    context 'pressed enter without any input' do
      let(:entered_value) { nil }


      it 'prints invalid output' do
        expect(stdout).to receive(:puts).with("Input an integer 5 or above")
        expect(stdout).to receive(:puts).with("Invalid. Try again:")

        subject.ask_for_number
      end
    end
  end
end