gpt4 book ai didi

ruby - 如何使用 rspec 测试 CLI 的标准输入

转载 作者:数据小太阳 更新时间:2023-10-29 07:24:00 24 4
gpt4 key购买 nike

我正在制作一个小的 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

我已经成功测试了使用以下代码执行文件中包含的命令:

spec/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的形式如下:

support/utilities.rb

def valid_test_data
[
{
input: "C1 ARGS\r
C2\r
C3\r
C4",
output: "OUTPUT\n"
}
# ...
]
end

我现在想做的是完全相同的事情,但不是从"file"中读取每个命令并执行它,我想以某种方式模拟用户输入 stdin。下面的代码完全错误,但我希望它能传达出我想去的方向。

spec/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) ,并且通常会重新安排这段代码很多,但似乎无法让我的任何 stub 将数据放入标准输入。我不知道我是否可以像处理命令文件一样解析我期望的命令行输入集,或者我应该使用什么代码结构来解决这个问题。如果对命令行应用程序进行了规范的人可以插话,那就太好了。谢谢。

最佳答案

我认为一些间接的方式可以帮助您为此代码编写单元测试,而不是对整个宇宙进行 stub 。您可以做的最简单的事情是允许注入(inject)用于输出的 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。

无论哪种方式,您都将从使代码更易于测试中受益。

关于ruby - 如何使用 rspec 测试 CLI 的标准输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12673485/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com