首页 > 解决方案 > 如何使用 rspec 为 HighLine gem 测试 IO?

问题描述

我有一堂课:

class Asker

  def initialize
    @cli = HighLine.new
  end 

  def exit_or_continue
    answer = @cli.ask "Type 'quit' to exit at any time, Press 'Enter' to continue"
    exit(0) if answer == 'quit'
  end
end

我该如何测试该exit_or_continue方法?

标签: rubyhighline

解决方案


据我了解,您想exit_or_continue根据用户输入测试方法。在这种方法中,有两个主要的重要事项。其中一个是执行的用户输入,@cli.ask另一个是exit如果用户输入是 则退出程序的方法quit

为了测试这些流程,我们需要同时存根Kernel.exitHighLine#ask方法。首先,我们覆盖类Kernel.exit实例中的方法Asker。该Kernel模块包含在类中,并且每个类都隐式地在 ruby​​ 中Object扩展类。Object所以我们的Asker类有Kernel默认的方法。

为什么我们exit在类的实例中存根方法Asker是因为如果我们在全局(在内核中)存根它会导致意想不到的问题。更重要的是,除非我们 stub 这个方法 rspec 退出并且其余的测试都不会运行。

其次,我们需要存根HighLine#ask方法等待来自客户端的输入。HighLine#ask是方法,这Kernel.gets在引擎盖下使用。通过存根这个方法,基本上我们说'请返回这个值,不要等待用户输入。'。换句话说,@cli.stub(ask: 'quit')这将返回quit或您想要的任何内容,而无需提示。

所以我认为以下测试将满足您的需求。如果您遇到任何问题,请随时发表评论。

RSpec.describe Asker do

  describe '#exit_or_continue' do
    before do
      @asker = Asker.new
      @cli = @asker.instance_variable_get('@cli')
      @asker.stub(exit: true) # We override Kernel.exit method inside asker instance
    end

    context 'when user input is quit' do
      it 'returns true' do
        @cli.stub(ask: 'quit') # We stub HighLine#ask method to return quit on behalf of the user.
        expect(@sker.exit_or_continue).to be(true)
      end
    end
    context 'when user is input is NOT quit' do
      it 'returns nil' do
        @cli.stub(ask: 'invalid response') # We stub HighLine#ask method to return invalid response on behalf of the user.
        expect(@sker.exit_or_continue).to be_nil
      end
    end
  end
end

推荐阅读