如何用RSpec测试Ruby中含TTY::Prompt的Timeout.timeout功能?
测试带超时的TTY::Prompt交互功能
首先修正原代码的异常捕获问题:原代码的rescue块写在Timeout.timeout的内部block里,无法捕获Timeout::Error(该异常由Timeout.timeout方法本身抛出,而非block内部)。修正后的代码如下:
require "tty-prompt" require "timeout" def prompt_with_timeout(timeout_duration = 60) prompt = TTY::Prompt.new response = "" begin Timeout.timeout(timeout_duration, Timeout::Error) do response = prompt.yes?("Do you agree?") end rescue Timeout::Error => e puts "Prompt timed out!" exit 1 end if response == true || response == "y" || response == "yes" # 同意逻辑 else # 不同意逻辑 end end
RSpec测试用例
以下是验证超时功能的完整RSpec测试代码:
require "rspec" require "timeout" require_relative "./your_script_name" # 替换为你的脚本文件名 RSpec.describe "#prompt_with_timeout" do let(:prompt) { double("TTY::Prompt") } before do # 模拟TTY::Prompt实例,避免真实交互 allow(TTY::Prompt).to receive(:new).and_return(prompt) # 让yes?方法长时间阻塞,模拟用户无输入 allow(prompt).to receive(:yes?).and_wrap_original do |m, *args| sleep 10 end end it "输出超时提示并以状态码1退出" do # 验证标准输出内容 expect { prompt_with_timeout(1) }.to output("Prompt timed out!\n").to_stdout # 验证退出状态码 expect { prompt_with_timeout(1) }.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) } end end
测试代码说明
- 模拟TTY::Prompt:用
double创建模拟对象,替代真实的交互式提示组件,避免测试过程中出现阻塞的交互窗口。 - 模拟无输入场景:让
yes?方法睡眠10秒,模拟用户长时间不输入的状态,确保超时逻辑被触发。 - 短超时触发验证:调用方法时传入1秒超时参数,强制触发
Timeout::Error。 - 输出与状态校验:
- 用
output(...).to_stdout检查超时提示文本是否正确输出。 - 捕获
SystemExit异常,验证程序退出状态码为1。
- 用
内容的提问来源于stack exchange,提问作者ahasunos
相关产品推荐
相关产品推荐

