0

How do I test a method for a message using RSpec? Basically my method accepts 2 parameters and if the right details have been supplied they should see a success message. I have tried this:

DRINKS_MACHINE = {
  'Coca Cola' => 2.99,
  'Fanta' => 3.27,
  'Beer' => 5.99
}

class Drink
  def check_money(drink_selection, money_amount_paid)
    amount_paid = money_amount_paid.to_f
    if amount_paid <= 0
      raise ArgumentError, 'Insert Money'
    end
    if not DRINKS_MACHINE.has_key?(drink_selection)
      raise ArgumentError, "Invalid selection: #{drink_selection}"
    end
    cost = DRINKS_MACHINE[drink_selection]
    if amount_paid < cost
      remainder = amount_paid - cost
      raise ArgumentError, "Not enough coins. Insert #{remainder} more!"
    elsif
      puts "Purchase Complete: #{drink_selection}"
    end
  end
end

I wish to test that when a valid selection and enough money is passed to the method the correct message is returned. In this case the message will also include the string variable that was passed to the method. I have tried the following: expect @method.check_money("Coca Cola", "5.00").raise ("Purchase Complete : Coca Cola"). Have also tried @method.check_money("Coca Cola", "4.59").should eq ("Purchase Complete: Coca Cola")

3
  • 1
    Is "Purchase Complete" returned by the method or is it an exception raised? Commented Mar 31, 2013 at 16:34
  • What exactly does check_money does? Commented Mar 31, 2013 at 16:35
  • the method check money, basically takes 2 parameters and checks that enough money has been supplied for the product. In this case it has so it the message should be 'Purchase Complete' @depa - no, this is not an exception, this is what is returned by the method Commented Mar 31, 2013 at 16:43

2 Answers 2

2

There are two different problems here, one with your spec and another in your method.

In your spec, you should use eq as a matcher since you're expecting a returned string from the check_money method.

@method.check_money("Coca Cola", "5.00").should eq("Purchase Complete: Coca Cola")

In your method, you should use simply

"Purchase Complete: #{drink_selection}"

and get rid of the puts, because that's outputting to console instead of returning the string.

Also, switch elsif for else in the previous line.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks Depa. I tried that but got the error - expected: "Purchase Complete" got: nil (compared using ==)
That means the spec is working, but the implementation code is not returning the expected string. Are you sure the second parameter is a string rather than a float?
Ah OK. - Well the return message also includes the product. So it's like this: - "Purchase Complete: #{drink_selection}" Drink selection is the string variable that is taken, in this case Coca Cola. Can I pass this variable to my test code? I wasnt able to find a way to do it, so I was just looking for the text Purchase Complete...
Perhaps you should update your question with the full code of that method, because there is more to this than you told us in the first place...
I have updated the original questions with the code and what I am trying to do. Hopefully this makes more sense now...
|
2

Simplify Your Use Case

When you have problems testing a method, you need to simplify it rather than trying to solve for a big ball of mud.

Your Logic and Syntax are Wrong

Your syntax has a number of glaring problems. This isn't Code Review Stack Exchange, but I strongly recommend refactoring your code so that it's less confusing. In particular, I'd stop raising exceptions all over the place for likely results. You could make your life a lot simpler with a good case statement.

Your Class and Test, Refactored

The following code exercises the core functionality you're looking for in your class:

class Drink
  DRINKS_MACHINE = {
    'Coca Cola' => 2.99,
    'Fanta'     => 3.27,
    'Beer'      => 5.99
  }   

  def check_money(drink_selection, money_amount_paid)
    amount_paid = money_amount_paid.to_f
    cost = DRINKS_MACHINE[drink_selection]
    if amount_paid < cost
      remainder = amount_paid - cost
      raise ArgumentError, "Not enough coins. Insert #{remainder} more!"
    else
      "Purchase Complete: #{drink_selection}"
    end
  end
end

describe Drink do
  describe '#check_money' do
    it 'sells a drink' do
      subject.check_money('Coca Cola', 2.99).should == "Purchase Complete: Coca Cola"
    end
  end
end

In particular, you need to return a result from your method (#puts returns nil) and ensure that your DRINKS_MACHINE constant is available to both your class and your spec.

2 Comments

Thanks CodeGnome for your input. I am a complete newbie to Ruby and Rspec so I am making a lot of mistakes. The code refactored looks much better and I am going to try that now. How can I make the DRINKS_MACHINE constant available to both the class and spec? These are currently 2 different .rb files. I tried using a require 'Drinks' at the top of my spec file but the test don't run when I insert that....
@user1523236 You make it part of the module or class under test, as I did in the example above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.