编写rspec测试以将项添加到哈希

时间:2015-04-22 21:00:46

标签: ruby rspec

我收到NoMethodError 对于我的代码,但我已经定义了它说缺少的add方法。 我正在尝试将项添加到已存在的哈希。  哈希是菜肴,我正在尝试使用add方法。

测试:

require 'menu'

describe Menu do

    it 'has a menu' do
        expect(subject.respond_to?(:dishes)).to be true
    end

    it 'displays dishes and prices' do
        expect(subject.dishes).to eq [
            { name: 'Burger', price: 10.95 },
            { name: 'Pizza', price: 14.00 },
            { name: 'Salad', price: 7.60 },
            { name: 'fries', price: 2.90 }
        ]
    end

    it 'can add dishes to it' do
        menu = Menu.new 
        menu.add_dish("Icecream", 4.80)
        expect(subject.dishes).to eq [
            { name: 'Burger', price: 10.95 },
            { name: 'Pizza', price: 14.00 },
            { name: 'Salad', price: 7.60 },
            { name: 'fries', price: 2.90 },
            { name: 'icecream', price: 4.80 }
        ]
    end
end

方法

class Menu
   def initialize
     @dishes = []
   end

   def dishes
     @dishes = [
        { name: 'Burger', price: 10.95  },
        { name: 'Pizza', price: 14.00 },
        { name: 'Salad', price: 7.60 },
        { name: 'fries', price: 2.90 }
     ]
   end

   def add_dish(name, price)
     @dishes << { name: name, price: price }
   end
end

谢谢

2 个答案:

答案 0 :(得分:1)

啊,我看到了你的问题。您需要初始化菜单。 Add不是静态方法。所以你需要类似的东西,

Menu.new.add(blah, blah)

看看:

Menu.add("Icecream", 4.80)

这种方法错了。它必须是:

Menu.new.add("Icecream", 4.80)

或者你需要类似的东西:

menu = Menu.new
menu.add("Icecream", 4.80)

答案 1 :(得分:1)

Ryan-Neal Mes的答案解决了NoMethodError,但您的代码中还有许多其他问题。

  1. 你重复自己,你应该让你的代码变干(不要重复自己的原则)

  2. 虽然你想在菜单列表中添加一个哈希值,它自己是一个哈希列表,你强制需要调用add方法的对象以特定的顺序提供参数,而不是方法构造哈希,所以每次你需要调用它时,你需要返回它来查看参数的顺序。

  3. dishes方法错误,因为每次调用它时,它都会将初始数组分配给@dishes变量。在这种情况下,add_dishes方法将无效,因为下次调用dishes方法时将删除添加的菜肴。
  4. 您的示例不具有表现力,因此如果测试没有通过,您无法从打印的消息中知道问题是什么。好吧,在这个小例子中这不是什么大问题,但在一个大的应用程序中,规格表达具有更高的价值。
  5. 这里的测试例子

    require 'menu'
    
    describe Menu do
      # every time you call the function dishes in an example
      # it will be declared and it will return this array
      let :dishes do
        [
          { name: 'Burger', price: 10.95 },
          { name: 'Pizza', price: 14.00 },
          { name: 'Salad', price: 7.60 },
          { name: 'fries', price: 2.90 }
        ]
      end
    
      # explicit definition of the subject
      subject { Menu.new }
    
      # a shorter yet more expressive version of
      # expect(subject.respond_to?(:dishes)).to be true
      it { is_expected.to respond_to(:dishes) }
    
      # You should always group the examples that test 
      # the same method
      describe '#dishes' do
        # it 'displays dishes and prices' do
        it 'returns the list of dishes' do
          expect(subject.dishes).to eq dishes
        end
      end
    
      describe "#add_dish" do
        # it 'can add dishes to it' do
        it "adds the given dish to the list of dishes" do
          new_dish = {name: 'salad', price: 4.0 }
          expect {
            subject.add_dish(new_dish)
          }.to change(subject.dishes, :count).by(1)
          expect(subject.dishes).to include new_dish
        end
      end
    end
    

    所以这里是类定义

    class Menu
      # you don't need to declare the method dishes
      # since this is what attr_reader will do
      attr_reader :dishes
    
       def initialize
         # this will set the @dishes only once
         # but you code @dishes = [...] will return
         # the same list every time you call it and
         # all the dishes you add through the #add method
         # will be deleted.
         @dishes = [
            { name: 'Burger', price: 10.95  },
            { name: 'Pizza', price: 14.00 },
            { name: 'Salad', price: 7.60 },
            { name: 'fries', price: 2.90 }
         ]
       end
    
       # dish is a hash {name: '', price: ''} 
       def add_dish(dish)
         @dishes << dish
       end
    end
    

    所以现在运行rspec --format doc --color并查看消息的表达方式。