Ruby 给出奇怪结果的检验系统
所以我正在制作一个类似于的结账系统。但是,我有3个项目(A、B和C分别定价为3.11美元、5.00美元和11.23美元) 条件是,项目A有一个买一送一的优惠,如果购买3套或更多,项目B将降至4.50美元。测试代码时会出现问题 我编写了以下代码来解决这个问题: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
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))