Rspec测试未按指定范围执行插入,请求排查问题
解决Rspec测试中批量插入数据库的命令丢失问题
问题背景
运行Rspec测试时遇到异常:测试需向C语言实现的数据库db执行批量插入,指定范围为1到1384时可正常完成1384次插入;但指定超过1384的范围时,仅执行1348次插入。已通过检查表数据验证问题,编译C程序时使用-Wall -Wextra -g3参数未发现错误,且C程序本身插入功能正常,推测问题出在测试代码中。
原测试代码:
require 'rspec' describe 'database' do def run_script(commands) raw_output = nil IO.popen("./db", "r+") do |pipe| commands.each do |command| pipe.puts command end pipe.close_write # Read entire output raw_output = pipe.gets(nil) end raw_output.split("\n") end it 'prints error message when table is full' do script = (1..1384).map do |i| "insert #{i} user#{i} person#{i}@example\n" end script << ".exit" result = run_script(script) expect(result[-2]).to eq("db > Error: Table full.") end end
问题原因
原测试代码中使用IO.popen批量写入所有命令后再一次性读取输出,这种方式存在管道缓冲区溢出或命令未被完整处理的风险:
- 快速写入大量命令时,管道缓冲区可能被填满,导致部分命令无法被数据库进程及时读取
- 数据库进程处理命令需要时间,测试代码未等待每条命令处理完成就关闭写入端,导致后续命令丢失
修复方案
修改run_script方法,改为逐行写入命令并同步等待处理完成,确保每条命令都被数据库进程接收并处理:
require 'rspec' describe 'database' do def run_script(commands) output = [] IO.popen("./db", "r+") do |pipe| commands.each do |command| pipe.puts command # 等待数据库返回提示符,确认当前命令已处理完成 loop do line = pipe.gets break if line.nil? || line.include?("db > ") output << line.chomp end end pipe.close_write # 读取剩余的输出内容 while (line = pipe.gets) output << line.chomp end end output end it 'prints error message when table is full' do # 测试超过容量的范围,比如1到1385 script = (1..1385).map do |i| "insert #{i} user#{i} person#{i}@example" end script << ".exit" result = run_script(script) # 改用包含断言,避免依赖输出行的索引 expect(result).to include("db > Error: Table full.") end end
关键修改点
- 移除命令字符串末尾的
\n:pipe.puts会自动添加换行符,重复添加可能导致数据库解析错误 - 同步等待处理结果:每次写入命令后,循环读取输出直到出现
db >提示符,确保当前命令已被数据库处理 - 优化输出收集逻辑:分阶段读取输出,避免一次性读取导致的内容截断
- 调整断言方式:从依赖行索引改为检查是否包含目标错误信息,提升测试稳定性
额外排查建议
- 运行测试时可以打印
result内容,查看实际输出是否有异常响应或丢失的命令反馈 - 确认数据库表的实际容量上限是否为1384条,避免因预期值错误导致的测试偏差
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

