如果我的问题不完全清楚,请原谅我。我已经醒了太久了,我感觉自己有点脑死了。
我正在进行Ruby练习,我无法弄清楚为什么我的rspec测试没有通过我认为会起作用的东西。
require 'date'
class Product
attr_accessor :photo_src, :promotion, :initial_date
attr_reader :default_photo, :default_price, :current_price
def initialize(name, photo, price)
@name = name
@default_photo = photo
@photo_src = photo
@default_price = price
@current_price = price
@initial_date = Date.today.yday
@promotion = false
end
def price_change(sale_price)
calculator = RedPencilCalculator.new(self)
if promotion
if sale_price > @current_price
calculator.end_promotion!
elsif sale_price < (@default_price - (@default_price * 0.3))
calculator.end_promotion!
end
else
calculator.start_promotion!
end
@current_price = sale_price
end
end
class RedPencilCalculator
attr_accessor :promotion_start, :product
def initialize(product)
@product = product
end
def start_promotion!
if start_promotion?
product.promotion = true
product.photo_src = "redX.png"
@promotion_start = Date.today.yday
end
end
#would need to run daily
def end_promotion?
promotion_duration
if @duration == 30 || @duration == 335
end_promotion!
end
end
def end_promotion!
product.promotion = false
product.photo_src = product.default_photo
product.initial_date = Date.today.yday
end
private
def calculate_range
@min_discount = product.default_price - (product.default_price * 0.05)
@max_discount = product.default_price - (product.default_price * 0.3)
end
def start_promotion?
calculate_range
@max_discount <= product.current_price && product.current_price <= @min_discount && Date.today.yday - product.initial_date >= 30
end
def promotion_duration
current_date = Date.today.yday
@duration = current_date - @promotion_start
end
end
Rspec的
这不起作用:
describe Product do
let(:shoes) { Product.new("shoes", "item.png", 100) }
it 'should change the photo_src and promotion attribute if applicable' do
allow(shoes).to receive(:initial_date) { 100 }
shoes.price_change(75)
expect(shoes.promotion).to eq(true)
expect(shoes.photo_src).to eq("redX.png")
end
end
这样做:
describe Product do
let(:shoes) { Product.new("shoes", "item.png", 100) }
let(:calculator) { RedPencilCalculator.new(shoes) }
it 'should change the photo_src and promotion attribute if applicable' do
allow(shoes).to receive(:initial_date) { 100 }
shoes.price_change(75)
calculator.start_promotion!
expect(shoes.promotion).to eq(true)
expect(shoes.photo_src).to eq("redX.png")
end
end
所以在我看来,start_promotion! price_change方法中的方法调用无效。
答案 0 :(得分:1)
我没有针对您的错误的具体答案,但有一些关于如何查明问题的建议。
你在一次单元测试中测试太多了。有太多可能出错的地方(正如你所发现的那样)很难找到错误的位置。即使你现在正在努力,当某些东西在轨道上发生变化时(因为它不可避免地会发生),它至少会像现在一样难以调试。
简化初始化程序。它应该只设置@ name,@ photo,@ price。其他实例变量应该是方法(写测试除非它们是私有的)。
您怀疑RedPencilCalculator#start_promotion!
有错误。写一个测试来消除这种可能性。
随着更多测试的到位,这个bug最终会被逼入绝境并被粉碎!
最后 - 这说起来容易做起来难 - 但是先尝试编写测试。它很难但变得更容易,甚至更有乐趣!
答案 1 :(得分:0)
start_promotion?
放在里面,就像这样:
p "got past calc range: #{@max_discount.inspect} and #{@min_discount.inspect} and #{product.current_price}"
得到了:
"got past calc range: 70.0 and 95.0 and 100"
鉴于以下行检查当前价格少而不是最小折扣... 这就是你必须检查/修复以使其有效的方法