RSpec测试ActiveRecord Flight模型around_date作用域报错求助
问题:RSpec测试ActiveRecord作用域时出现NoMethodError(undefined method `>=')
测试代码
let(:flight) { create(:flight) } date = DateTime.new(year=2023, month=12, day=25) it 'selects within default date range' do flights = Flight.around_date(date.to_s).to_a expect flights.to include(flight) end
Flight模型的around_date作用域代码
scope :around_date, ->(date_string, day_interval = 1) { if date_string.present? date = Date.parse(date_string) lower_date = date - day_interval.days upper_date = date + day_interval.days where(start_datetime: (lower_date..upper_date)) end }
运行测试时的错误信息
Failure/Error: expect flights.to include(flight) NoMethodError: undefined method `>=' for #<RSpec::Matchers::BuiltIn::ContainExactly:0x00007fe400279098 @expected=[#<Flight id: 1, departure_airport_id: 2, arrival_airport_id: 1, start_datetime: "2023-12-25 00:00:00.000000000 +0000", duration_minutes: 30, created_at: "2023-12-02 16:51:32.363329000 +0000", updated_at: "2023-12-02 16:51:32.363329000 +0000">]> # ./spec/models/flight_spec.rb:11:in `block (4 levels) in <main>'
错误原因及解决方法
这个错误的根源是RSpec断言的语法错误:你在写expect flights.to include(flight)时没有给expect加上括号,导致Ruby错误解析了代码结构。
Ruby中方法调用的优先级会让expect flights.to include(flight)被解析为:
expect(flights.to(include(flight)))
也就是把include(flight)作为参数传给了flights.to方法,但实际上to是RSpec Expectation的方法,应该在expect(flights)这个对象上调用,而不是在flights数组上调用。这种错误的解析导致RSpec内部的Matcher对象被错误地当作参数传递,进而触发了不存在的>=方法调用。
解决方法
给expect加上括号,修正断言语法:
expect(flights).to include(flight)
额外注意点
另外,你的作用域中用Date类型的范围去匹配start_datetime(DateTime类型)时,ActiveRecord会自动把start_datetime转换为Date进行比较,这部分逻辑是没问题的,但如果你的start_datetime包含具体时间且需要更精确的范围,可能需要把lower_date和upper_date转换为DateTime类型(比如lower_date.beginning_of_day和upper_date.end_of_day),避免漏掉当天晚些时候的航班。
内容的提问来源于stack exchange,提问作者blainefreestone
相关产品推荐
相关产品推荐

