如何在DockingStation类中调用Bike类的broken?方法,实现不发放损坏自行车功能并通过RSpec测试
问题:RSpec测试未触发预期异常(无法过滤损坏自行车)
现有代码
DockingStation & Bike 实现
class DockingStation attr_reader :bikes, :capacity attr_accessor :capacity DEFAULT_CAPACITY = 20 def initialize(capacity = DEFAULT_CAPACITY) @bikes = [] @capacity = capacity end def release_bike fail 'No bikes available' if empty? @bikes end def dock(bike) fail 'bike full' if full? @bikes << bike end def full? @bikes.count >= DEFAULT_CAPACITY end def empty? @bikes.empty? end private :full? , :empty? end class Bike def working? true end def report_broken @broken = true end def broken? @broken end end
RSpec 测试
require './lib/docking_station.rb' require './lib/bike.rb' describe DockingStation do describe 'initialization' do subject{DockingStation.new} let(:bike) {Bike.new} it 'default capacity' do described_class::DEFAULT_CAPACITY.times do subject.dock(bike) end expect{ subject.dock(bike) }.to raise_error 'bike full' end end it 'has a default capacity' do expect(subject.capacity).to eq DockingStation::DEFAULT_CAPACITY end describe '#release_bike' do it 'releases a bike' do bike = Bike.new end it 'raises an error if bike is broken' do bike = Bike.new bike.report_broken subject.dock bike expect {subject.release_bike}.to raise_error 'No bikes available' end end end
问题描述
我希望上述RSpec测试能够通过,但始终收到「未触发预期异常」的错误。我的目标是让DockingStation不发放已通过report_broken方法标记为损坏的自行车,但broken?方法定义在Bike类中,因此无法在DockingStation的release_bike方法中直接编写fail 'bike broken' if broken?,因为DockingStation无法识别该方法。恳请提供正确的解决方向,帮助我实现需求并通过测试。
解决方案
问题根源分析
你的测试失败有两个核心原因:
release_bike方法当前只是返回整个@bikes数组,既没有移除要发放的自行车,也没有检查自行车是否损坏;full?方法硬编码使用了DEFAULT_CAPACITY,忽略了初始化时传入的自定义容量,这会导致初始化容量的测试逻辑潜在失效。
代码修改步骤
1. 修复DockingStation类的核心逻辑
修改release_bike和full?方法,让停靠站能识别并过滤损坏的自行车:
class DockingStation # ... 保留原有其他代码 ... def release_bike # 找到第一辆未损坏的自行车 available_bike = @bikes.find { |bike| !bike.broken? } fail 'No bikes available' unless available_bike # 从停靠站中移除这辆自行车并返回 @bikes.delete(available_bike) available_bike end def full? # 使用实例的@capacity而不是默认常量,支持自定义容量 @bikes.count >= @capacity end # ... 保留原有其他代码 ... end
2. 完善RSpec测试的断言逻辑
原测试中it 'releases a bike'没有任何断言,需要补充验证逻辑;同时确保损坏自行车的测试场景正确:
describe DockingStation do # ... 保留原有初始化相关测试 ... describe '#release_bike' do let(:working_bike) { Bike.new } let(:broken_bike) { Bike.new.tap(&:report_broken) } it 'releases a working bike' do subject.dock(working_bike) released_bike = subject.release_bike expect(released_bike).to be_a(Bike) expect(released_bike.working?).to be true # 验证自行车已从停靠站移除 expect(subject.bikes).not_to include(released_bike) end it 'raises an error if only broken bikes are available' do subject.dock(broken_bike) expect { subject.release_bike }.to raise_error 'No bikes available' end it 'raises an error if no bikes are available' do expect { subject.release_bike }.to raise_error 'No bikes available' end end end
关键逻辑说明
- 在
release_bike中,我们通过@bikes.find { |bike| !bike.broken? }遍历停靠站中的自行车,筛选出第一辆未损坏的;如果没有找到,就抛出错误。 - 使用
@bikes.delete(available_bike)确保发放的自行车从停靠站中移除,符合真实场景的"释放"逻辑。 full?方法改用实例变量@capacity,保证初始化时传入的自定义容量能正常生效。
这样修改后,你的测试就能正确触发预期异常,同时停靠站也能实现只发放可用自行车的需求。
内容的提问来源于stack exchange,提问作者hibscodes
相关产品推荐
相关产品推荐

