Ruby 给出奇怪结果的检验系统

Ruby 给出奇怪结果的检验系统,ruby,Ruby,所以我正在制作一个类似于的结账系统。但是,我有3个项目(A、B和C分别定价为3.11美元、5.00美元和11.23美元) 条件是,项目A有一个买一送一的优惠,如果购买3套或更多,项目B将降至4.50美元。测试代码时会出现问题 我编写了以下代码来解决这个问题: class PriceDiscount # Applies price discounts for a specific number of items # Initial method with item price and item

所以我正在制作一个类似于的结账系统。但是,我有3个项目(A、B和C分别定价为3.11美元、5.00美元和11.23美元)

条件是,项目A有一个买一送一的优惠,如果购买3套或更多,项目B将降至4.50美元。测试代码时会出现问题

我编写了以下代码来解决这个问题:

class PriceDiscount  # Applies price discounts for a specific number of items

# Initial method with item price and item quantity parameters
  def initialize(itemprice, quantity)
    @itemprice = itemprice
    @quantity = quantity
  end

# "calculate_for" method which calculates the discount for the specific number of items
  def calculate_for(quantity)
    (quantity / @quantity).floor * @itemprice
  end

end


class PricePolicy  # Calculates the price for a certain quantity of items after discounts

# Initial method with the original price and discounts as the paremeters
  def initialize(orgprice, *discounts)
    @orgprice = orgprice
    @discounts = discounts
  end

# Calculates the discounted price of a number of items
  def price_for(quantity)
    quantity * @orgprice - discount_for(quantity)
  end

# Calculates the discount which is given for a number of items
  def discount_for(quantity)
    @discounts.inject(0) do |mem, discount|
      mem + discount.calculate_for(quantity)
    end
  end
end


# Rule list set up for great flexibility as each rule is specified in one line
RULES = {
  'A' => PricePolicy.new(3.11, PriceDiscount.new(3.11, 2)), 
  'B' => PricePolicy.new(5.00, PriceDiscount.new(4.50, 2)),
  'C' => PricePolicy.new(11.23),
}


class Checkout # Checkout class which applies the rules to each item that is scanned

# Initial method which has the rules and items as its parameters
  def initialize(rules)
    @rules = rules
    @items = Hash.new
  end

# Method to set up the array in which scanned items are stored
  def scan(item)
    @items[item] ||= 0
    @items[item] += 1
  end

# Method which totals the price of the scanned items
  def total
    @items.inject(0) do |mem, (item, quantity)|
      mem + price_for(item, quantity)
    end
  end

  private 
  def price_for(item, quantity)
    if rule_for(item)
      rule_for(item).price_for(quantity)
    else
      raise "Invalid item '#{item}'"
    end
  end

  def rule_for(item)
    @rules[item]
  end
end
这是测试仪:

require 'test/unit'
require_relative './CheckoutSystem.rb'

class TestPrice < Test::Unit::TestCase

  def price(goods)
    co = Checkout.new(RULES)
    goods.split(//).each { |item| co.scan(item) }
    co.total
  end


  def test_totals

    # Scenario 1 with basket: A, B, A, A, C
    assert_equal(22.45, price("ABAAC").round(2))

    # Scenario 2 with basket: A, A
    assert_equal(3.11, price("AA").round(2))

    # Scenario 3 with basket: B, B, A, B
    assert_equal(16.61, price("BBAB").round(2))
  end

end
要求“测试/单元”
需要_relative./CheckoutSystem.rb'
类TestPrice
场景1和场景2给出了正确的值。然而,场景3给出了13.11美元的值,而实际上它应该是16.61美元


有人知道我在哪里犯了错误吗?我已经检查了好长时间,无法修复它。任何帮助都将不胜感激

为了更改程序以通过测试用例,您必须更改:

'B' => PricePolicy.new(5.00, PriceDiscount.new(4.50, 2)),

这样,当用户购买3个“B”项目时,他们将获得1.5的折扣,这意味着3个项目的总价将从15变为13.5(每个项目4.50)

注意,在这种情况下,如果用户购买4个“B”项目,他们将在前3个项目上获得折扣,但在第4个项目上没有折扣


为了解决在购买“3件或更多物品”时正常工作的问题,必须更改方法的折扣.calculate\u。这是因为“A”和“B”项目的折扣计算方式不同:

一个简单的实现是为每种情况定义一个“类型”。在下面的示例中,空类型仅表示“x或更多项目”情况,而bogo类型表示“购买x并获得固定折扣”情况

class PriceDiscount
  def initialize(itemprice, quantity, type = nil)
    @itemprice = itemprice
    @quantity = quantity
    @type = type
    raise "Invalid type '#{type}'" if @type != 'bogo' && @type != nil
  end

  def calculate_for(quantity)
    if (@type == 'bogo')
      (quantity / @quantity) * @itemprice
    elsif quantity >= @quantity
      (quantity.to_f / @quantity) * @itemprice
    else
      0
    end
  end
end
规则将更新如下:

RULES = {
  'A' => PricePolicy.new(3.11, PriceDiscount.new(3.11, 2, 'bogo')), 
  'B' => PricePolicy.new(5.00, PriceDiscount.new(1.50, 3)),
  'C' => PricePolicy.new(11.23),
}
bogo项目将使用与您之前相同的计算方法,即AA有1个折扣,AAA有1个折扣,AAAA有2个折扣。 “x个或多个项目”将首先检查项目数量是否符合阈值,如果符合阈值,则将对这些项目中的每个项目应用折扣率。(在这种情况下,BBB将应用指定的折扣1.50。BBBB将应用折扣-->2.00的修改版本,以匹配这4项。)

此外,您还可以删除ints-->的“.floor”方法,该方法将在转换时自动进行floor。为了得到非整数结果,您可以看到我已经将第二次计算中的一个值转换为浮点值

尝试使用这些特定于更改的测试运行这些更改:

assert_equal(13.11, price("BBA").round(2))
assert_equal(21.11, price("BBBBA").round(2))
assert_equal(22.45, price("AAAABC").round(2))
assert_equal(25.56, price("AAAAABC").round(2))

非常感谢您的详细回答!我将尝试实现您现在描述的固定代码。
assert_equal(13.11, price("BBA").round(2))
assert_equal(21.11, price("BBBBA").round(2))
assert_equal(22.45, price("AAAABC").round(2))
assert_equal(25.56, price("AAAAABC").round(2))