在另一个类中创建类的实例

时间:2014-08-15 00:21:24

标签: ruby rspec

如果我的问题不完全清楚,请原谅我。我已经醒了太久了,我感觉自己有点脑死了。

我正在进行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方法中的方法调用无效。

2 个答案:

答案 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"

鉴于以下行检查当前价格而不是最小折扣... 这就是你必须检查/修复以使其有效的方法