ruby - 在测试永无止境的流程时,如何从测试中停止流程?

标签 ruby testing spawn

我正在用 Ruby 开发一个长时间运行的程序。我正在为此编写一些集成测试。这些测试需要在启动后杀死或停止程序;否则测试挂起。

例如,使用文件 bin/runner

#!/usr/bin/env ruby
while true do
  puts "Hello World"
  sleep 10
end

(集成)测试将是:

class RunReflectorTest < TestCase
  test "it prints a welcome message over and over" do
    out, err = capture_subprocess_io do
      system "bin/runner"
    end
    assert_empty err
    assert_includes out, "Hello World"
  end
end

只是,很明显,这是行不通的;测试开始并且永远不会停止,因为 system 调用永远不会结束。

我应该如何解决这个问题?是 system 本身的问题,Kernel#spawn 会提供解决方案吗?如果是这样,如何?以下内容以某种方式使 out 为空:

class RunReflectorTest < TestCase
  test "it prints a welcome message over and over" do
    out, err = capture_subprocess_io do
      pid = spawn "bin/runner"
      sleep 2
      Process.kill pid
    end
    assert_empty err
    assert_includes out, "Hello World"
  end
end

.这个方向似乎也会导致很多时间问题(和缓慢的测试)。理想情况下,读者将遵循 STDOUT 流,并在遇到字符串时立即让测试通过,然后立即终止子进程。我找不到如何使用 Process 执行此操作。

最佳答案

测试行为,而不是语言特性

首先,您正在做的是 TDD 反模式。测试应该关注方法或对象的行为,而不是像循环这样的语言特性。如果您必须测试循环,请构建一个测试来检查有用的行为,例如“输入无效的响应会导致重新提示”。检查循环是否永远循环几乎没有用处。

但是,您可能决定通过检查以下内容来测试长时间运行的进程:

  1. 如果它在 t 时间后仍在运行。
  2. 如果至少执行了 i 次迭代。
  3. 如果在给定特定输入或达到边界条件时循环正确退出。

使用超时或信号结束测试

其次,如果你决定这样做,你可以用 Timeout::timeout 来逃避这个 block 。 .例如:

require 'timeout'

# Terminates block
Timeout::timeout(3) { `sleep 300` }

这既快速又简单。但是,请注意,使用超时实际上并不表示进程。如果运行几次,您会注意到 sleep 仍作为系统进程运行多次。

最好是在你想退出时用 Process::kill 向进程发出信号,确保您自己清理干净。例如:

pid = spawn 'sleep 300'
Process::kill 'TERM', pid
sleep 3
Process::wait pid

除了资源问题之外,当您生成有状态的东西并且不想影响测试的独立性时,这是一种更好的方法。只要有可能,您几乎应该总是在测试拆解中终止长时间运行(或无限)的进程。

关于ruby - 在测试永无止境的流程时,如何从测试中停止流程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44592263/

相关文章:

ruby - 检查散列是否有一个包含一些文本的键

PHP 等价于 Ruby 的 or-equals (foo ||=bar)?

ruby-on-rails - simple_form 显示 collection_select 上的当前值

testing - 没有代码覆盖率的 HttpParameterBinding

javascript - Node.js 生成 'echo $(python --version)'

javascript - 如何在将鼠标指针移到按钮上时显示更多信息?

testing - 如何在 Cucumber-QAF 设置中跳过通过的测试用例

reactjs - 如何测试解决 promise 然后在 React 中更改状态的方法?

javascript - Node.js通过spawn()调用bash脚本: ENOENT

node.js - 使用自己的控制台窗口生成新的子进程