使用RSpec测试控制台应用程序交互

时间:2016-03-09 02:37:02

标签: ruby unit-testing rspec console-application read-eval-print-loop

我有几个控制台应用程序,它们使用readline进行读取,评估,打印,循环(REPL),如果可能的话,我想创建使用RSpec的测试。我读过关于模拟课程的内容,但我看不出它们是如何工作的。是否只能替换实际的输入类来测试其余的类?我想对整个应用程序进行集成测试。对于我的一个Web服务,我有一个使用curl发送请求来测试套接字接口的rspec脚本。我想为控制台界面做类似的事情。我只是不理解模拟类的概念吗?

答案

基于@Dave Schweisguth给出的答案,我尝试了这个:

require 'rspec'
require 'pty'

describe "anthematic" do
  before(:all) do
    @output, @input = PTY.spawn('bin/anthematic')
  end

  it "turns on a zone" do
    @output.readpartial 1024 # read past the prompt
    @input.puts "on 1"
    expect(@output.readline.chomp).to eq("on 1")
    expect(@output.readline.chomp).to eq("turn on zone 1")
  end
end

我移动了产卵,所以我可以添加其他测试。我是rspec的新手,因此可能不是最干净的解决方案。

在研究PTY时,我发现this article涉及popen,pty和其他人的子流程。

3 个答案:

答案 0 :(得分:2)

我同意你的看法,对整个应用程序进行至少一次或几次集成测试会很好。那些测试不应该有嘲笑; mocks替换要隔离测试的类的依赖项。以下是使用irb作为示例集成测试命令行应用程序的简单方法:

ControllerClass

如果我有这样的多个测试,我会提取一个RSpec匹配器,但是我在这里留下了内容,以保持简单。

这种测试相对较慢,因为它在一个单独的进程中使用新的Ruby实例运行应用程序,因此您只想编写其中一个或几个来测试应用程序作为一个整体运行然后测试各个班级的单元测试的详细信息。那些看起来像是什么,以及你是否需要嘲笑,完全取决于你的应用程序的内部结构。

答案 1 :(得分:0)

因此,模拟在rspec测试中的作用是代表方法调用并给出预期的返回值。所以说在这种情况下,你有一个类来调用哈希,但你不想在你的规范中实际调用。

MyClass.get_info

或类似的东西。

在rpsec中,你可以做的是指定返回值/对象/调用该方法时的任何内容。要做到这一点,在规范的开头或之前的块中你会放

allow(MyClass).to receive(:get_info).and_return({ key: 'value' })

现在在规范中,对MyClass.get_info的任何调用都将返回指定的哈希值。

my_info = MyClass.get_info
# my_info = { key: 'value' }

答案 2 :(得分:0)

当某些内容难以实际测试或资源过于密集而无法测试时,您基本上会编写模拟内容。

在这种情况下,您要做的事情(REPL测试)很难但并非不可能。

我确定还有其他方法可以做到,但这是我使用过的方法:

步骤1 编写一个shell命令,将命令传递给REPL程序。

shell_cmd = %{(echo "MyClass.new.call_my_command"; echo "exit") | ruby my_repl_program.rb"}

这使用括号组合多个" echo"输出,然后发送到您的程序。请注意,需要发送退出命令,否则进程将挂起。

第2步调用shell命令并将变量设置为输出:

cmd_output = `#{shell_cmd}`

第3步验证输出

现在您可以根据需要测试cmd_output的值。