【问题标题】:How to test OptionParser with Rspec - RSpec options are stored in ARGV array during testing如何使用 Rspec 测试 OptionParser - RSpec 选项在测试期间存储在 ARGV 数组中
【发布时间】:2020-07-12 00:22:35
【问题描述】:

我正在学习 ruby​​ 并尝试使用 rspec 为以下方法编写单元测试:

def get()
    options = {}
    OptionParser.new do |opt|
      opt.banner = 'Usage: validate-gitlab-ci [options]'
                    
      opt.on('-f', '--yaml YAML-PATH', 'Path to .gitlab-ci.yml') { |o| options[:yamlFile] = o }
      opt.on('-l', '--base-url GitLab url', 'GitLab API url') { |o| options[:baseUrl] = o + API_PATH }
      opt.on('-t', '--timeout[TIMEOUT]', Integer, 'Api timeout in seconds') { |o| options[:timeout] = o || 10 }
      opt.on('-v', '--version', 'Program version') { |o| options[:version] = o }
    end.parse!
                
    validateUrl!(options[:baseUrl])
    validateYamlFile!(options[:yamlFile])

    @baseUrl = options[:baseUrl]
    @pathToYamlFile = options[:yamlFile]
end

到目前为止,我的单元测试代码是:

RSpec.describe Gitlab::Lint::Client::Args do
    describe "#get" do
        context "when arguments are valid" do
            it "sets baseUrl and pathToYamlFile" do
                io = StringIO.new
                io.puts "glab-lint --base-url=https://example.com --yaml=valid.ym\n"
                io.rewind

                $stdin = io
                args = Gitlab::Lint::Client::Args.new
                args.get()
                expect(args.baseUrl).to.eq("https://example.com")
            end
        end
    end
end

我正在尝试为 OptionParser 模拟 STDIN。但是,在执行测试时会显示以下错误:

 OptionParser::InvalidOption:
       invalid option: --pattern

这是由 end.parse 提出的! get() 方法中的一行

有没有人设法用 stdin 模拟测试 OptionsParser?

更新

我认为正在发生的事情是一些 RSpec 选项,例如--模式??在 STDIN 中被捕获并传递给脚本???或者.... RSpec 正在使用标准输入选项??

阅读此post 似乎表明使用 RSpec 无法实现所需的功能......如果这确实是真的,那么我将在未来迁移到使用替代测试框架来使用 ARGV 的 CLI 项目。有一个建议的解决方法 here 但建议使用环境变量来捕获命令行参数。在这种情况下,需要进一步重构被测软件,纯粹是为了适应 RSpec 测试框架的功能!!

如果我添加一个 puts 语句以在测试脚本中显示 ARGV 的内容,它确认是这种情况,输出如下:

--pattern
spec/**{,/*/**}/*_spec.rb
[--base-url=https://gitlab.com --yaml=valid.ym]

所以.....作为 RSpec 的新手.....我的选择是:

  1. 更新 get 方法的签名以接受 args 数组:
def get(args)
    options = {}
    OptionParser.new do |opt|
    ...
    end.parse!(args)
end

这延迟了测试从 ARGV 读取的代码进一步向上调用层次结构的问题

  1. 修改 ARGV 将前两个参数移出数组,然后在测试完成后将 ARGV 恢复到原始状态。看起来类似的东西已经尝试过here,但没有成功。

  2. 作为 RSpec 的新手,我不知道的其他一些配置

  3. 研究替代方案,例如minitest,那可能不修改ARGV数组??

有关选项 3 和 4 的更多信息表示赞赏....

【问题讨论】:

  • 哪一行导致错误?
  • @bobrodes 感谢您的回复,感谢 :) get 方法中的 end.parse! 行引发了错误
  • 对不起,我看到你提到了。这听起来不像您的测试套件的问题。您是否在测试套件之外运行了 #get 方法,例如 p args.baseurl
  • @bobrodes 谢谢,是的,已经尝试从 rspec 之外的控制台运行它并使用 puts 进行验证
  • 抱歉,我只有这些。 :) 根本不知道 RSpec;我使用迷你测试。祝你好运!

标签: ruby rspec


【解决方案1】:

您可以使用 RSpec 模拟 STDIN。例如:

STDIN.should_receive(:read).and_return("glab-lint --base-url=https://example.com --yaml=valid.yml")

或者,您可以使用反引号或system 调用您的实际命令行程序,并在响应上断言。

【讨论】:

  • 感谢@kgilpin 尝试了STDIN.should_receive 的代码,但收到关于 should_receive 未定义为方法的错误。尝试过allow(STDIN).to receive(:read).and_return("--base-url=https://example.com --yaml=valid.yml"),但运行测试时 url 为 nil。从 RSpec 之外的控制台运行程序显示正在为被测代码分配 url。
  • 更新了更多细节的问题....看起来 RSpec 的设计使得 ARGV 状态可用于所有测试脚本.....OptionParser 正在接收具有 RSpec 状态的 ARGV
猜你喜欢
  • 2017-09-24
  • 1970-01-01
  • 2013-07-04
  • 2018-04-26
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 2015-06-02
  • 2023-03-18
相关资源
最近更新 更多