我正在编写一个小的Ruby程序,但是无法想出如何编写RSpect测试来模拟多个用户命令行输入(功能本身可以正常工作)。我认为这个StackOverflow答案可能涵盖了我所在的最接近的领域,但不完全符合我的要求。我正在使用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
我现在想要做的事情与之前类似,但是不是从“文件”中读取每个命令并执行,而是希望模拟用户输入到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)
,并且经常重新排列这段代码,但似乎无法使我的存根将数据放入stdin中。我不知道是否可以像处理命令文件一样解析我从命令行预期的输入集,或者应该使用什么代码结构来解决此问题。如果有人已经规范化了命令行应用程序,请发表评论,谢谢。