Using assert:equals: in pharo

Viewed 632

I have the following program in Pharo: 2 classes Yacht and YachtRental, Test Class and YachtRental test. I need to implement the following: on the 4th day, the customer gets discount = 10 % on the daily rate. Here is my code:

I need to implement the following: on the 4th day, the customer gets discount = 10 % on the daily rate. Here is my code:

| yachtRental myCruise |
    yachtRental := YachtRental new.
    myCruise := Yacht cruise.
    self assert: (yachtRental priceFor: myCruise days: 4) = 890

Basically, I need to be able to implement the discount of 10 % here, however there is a message "Using assert:equals: produces better context on rule failure", could you please help me explain what is wrong with it.

3 Answers

assert: takes a boolean, whereas assert:equals: takes two expressions. And, assert: doesn't know what you are testing, but assert:equals: knows that you are testing for two things to be equal.

In case of your test failing, assert: cannot print a meaningful failure message since all the information it has access to is false, so all it can print is "I expected something to be true but it wasn't."

assert:equals: has access to the values of the two expressions and can thus print something like "I expected foo to be equal to bar".

Since good failure messages are one of the most important aspects of a test library, the authors of the test library are guiding you to use the more expressive assertions in their library instead of a generic "is this true?"

[Note: I am ignoring reflection here. Both methods could, of course, reflectively inspect the source code of the test.]

I think that the question is more about the coding of yachtRental priceFor: myCruise days: 4 than it is about the more subtle issue of #assert: versus #assert:equal: (which, BTW, Jög explained so clearly.)

Interesting enough, the coding of #priceFor:days:, apparently simple, raises some doubts about the test and the discount specification.

Should the discount be applied to every day of the rental period when the period is 4 or more days long? Or should it be applied to days 4, 5, etc.?

In the first case, the logic would be

priceFor: aYacht days: anInteger
  | price |
  price := aYacht dailyRate * anInteger.
  anInteger >= 4 ifTrue: [price := price * 0.9].
  ^price

and in the second

priceFor: aYacht days: anInteger
  | rate |
  rate := aYacht dailyRate.
  ^anInteger < 4
     ifTrue: [rate * anInteger.]
     ifFalse: [rate * 3 + (rate * 0.9 * (anInteger - 3))]

Mathematically, the first discount policy would total a price of

rate * 4 * 0.9

which must equal (pun intended) 890. This means that rate should satisfy

rate = 890 / (4 * 0.9) = 247.222222222222 

which is a rather funny amount, isn't it?

And what about the second policy. In this case we would have

rate * 3 + (rate * 0.9 * (4 - 3)) = 890

or

rate * (3 + 0.9) = 890

hence

rate = 890 / 3.9 = 228.205128205128 

which, again, doesn't look as a daily rental rate.

So, my conclusion is that the test must be wrong or the discount policy insufficiently specified.

The system is suggesting that you might want to use

self assert: (yachtRental priceFor: myCruise onDay: 4)
equals: 890

instead of just the #assert:

but it doesn’t really matter.

What you did is just fine.

Related