user1523236
user1523236

Reputation: 1463

How do I test a method for a string using RSpec?

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")

Upvotes: 0

Views: 2343

Answers (2)

Todd A. Jacobs
Todd A. Jacobs

Reputation: 84343

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.

Upvotes: 2

Marcelo De Polli
Marcelo De Polli

Reputation: 29291

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.

Upvotes: 2

Related Questions