ruby – 如何使用rspec测试CLI的stdin
我正在制作一个小型的
Ruby程序,无法弄清楚如何编写模拟多个用户命令行输入的RSpec规范(功能本身可行).我认为
this StackOverflow answer可能涵盖了离我最近的地方,但这并不是我需要的.我使用
Thor作为命令行界面,但我不认为这是Thor的任何问题.
程序可以从文件或命令行读取命令,并且我已经能够成功编写测试以读取执行它们.这是一些代码: cli.rb class CLI < Thor # ... method_option :filename,aliases: ['-f'],desc: "name of the file containing instructions",banner: 'FILE' desc "execute commands","takes actions as per commands" def execute thing = Thing.new instruction_set do |instructions| instructions.each do |instruction| command,args = parse_instruction(instruction) # private helper method if valid_command?(command,args) # private helper method response = thing.send(command,*args) puts format(response) if response end end end end # ... no_tasks do def instruction_set if options[:filename] yield File.readlines(options[:filename]).map { |a| a.chomp } else puts usage print "> " while line = gets break if line =~ /EXIT/i yield [line] print "> " end end end # .. end 我已经成功测试了使用以下代码执行文件中包含的命令: 投机/ cli_spec.rb describe CLI do let(:cli) { CLI.new } subject { cli } describe "executing instructions from a file" do let(:default_file) { "instructions.txt" } let(:output) { capture(:stdout) { cli.execute } } context "containing valid test data" do valid_test_data.each do |data| expected_output = data[:output] it "should parse the file contents and output a result" do cli.stub(:options) { { filename: default_file } } # Thor options hash File.stub(:readlines).with(default_file) do StringIO.new(data[:input]).map { |a| a.strip.chomp } end output.should == expected_output end end end end # ... end 并且上面提到的valid_test_data采用以下形式: 支持/ utilities.rb def valid_test_data [ { input: "C1 ARGSr C2r C3r C4",output: "OUTPUTn" } # ... ] end 我现在要做的是完全相同的事情,但不是从’文件’中读取每个命令并执行它,我想以某种方式模拟用户输入到标准输入.下面的代码是完全错误的,但我希望它可以传达我想要的方向. 投机/ cli_spec.rb # ... # !!This code is wrong and doesn't work and needs rewriting!! describe "executing instructions from the command line" do let(:output) { capture(:stdout) { cli.execute } } context "with valid commands" do valid_test_data.each do |data| let(:expected_output) { data[:output] } let(:commands) { StringIO.new(data[:input]).map { |a| a.strip } } it "should process the commands and output the results" do commands.each do |command| cli.stub!(:gets) { command } if command == :report STDOUT.should_receive(:puts).with(expected_output) else STDOUT.should_receive(:puts).with("> ") end end output.should include(expected_output) end end end end 我尝试在各个地方使用cli.stub(:puts),并且通常重新安排这些代码,但似乎无法获取我的任何存根来将数据放入stdin.我不知道我是否可以像命令文件一样解析命令行所期望的输入集,或者我应该用什么代码结构来解决这个问题.如果指定了命令行应用程序的人可以插入,那就太棒了.谢谢. 解决方法
我认为一些间接可以帮助你为这段代码编写一个单元测试,而不是对宇宙进行存根.您可以做的最简单的事情是允许注入输出的IO对象,并将其默认为STDOUT:
class CLI < Thor def initialize(stdout=STDOUT) @stdout = stdout end # ... @stdout.puts # instead of raw puts end 然后,在测试中,您可以使用StringIO来检查打印的内容: let(:stdout) { StringIO.new } let(:cli) { CLI.new(stdout) } 另一个选择是使用Aruba或类似的东西,并编写完整的集成测试,您实际运行您的程序.这也有其他挑战(例如非破坏性并确保不会挤压/使用系统或用户文件),但对您的应用程序将是一个更好的测试. Aruba是Cucumber,但断言可以使用RSPec匹配器.或者,你可以使用Aruba的Ruby API(没有文档,但公开并且效果很好)来做到这一点,而不需要Gherkin的麻烦. 无论哪种方式,您都将受益于使您的代码更加适合测试. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |