63

In the Ruby Koans, the section about_hashes.rb includes the following code and comment:

def test_changing_hashes
    hash = { :one => "uno", :two => "dos" }
    hash[:one] = "eins"

    expected = { :one => "eins", :two => "dos" }
    assert_equal true, expected == hash

    # Bonus Question: Why was "expected" broken out into a variable
    # rather than used as a literal?
end

I can't figure out the answer to the bonus question in the comment - I tried actually doing the substitution they suggest, and the result is the same. All I can figure out is that it is for readability, but I don't see general programming advice like that called out elsewhere in this tutorial.

(I know this sounds like something that would already be answered somewhere, but I can't dig up anything authoritative.)

Bruce
  • 8,202
  • 6
  • 37
  • 49

4 Answers4

92

It's because you can't use something like this:

assert_equal { :one => "eins", :two => "dos" }, hash

Ruby thinks that { ... } is a block, so it should be "broken out into a variable", but you can always use assert_equal({ :one => "eins", :two => "dos" }, hash)

Mike
  • 72
  • 1
  • 2
  • 9
Vasiliy Ermolovich
  • 24,459
  • 5
  • 79
  • 77
  • I totally like that answer, except that when I actually tried to substitute the hash as you suggest, it still worked fine and the assert passed. EDIT - no I didn't - I made the lesser change that left the assert comparing against 'true'. I'll try your suggestion and so I can watch it break. :) Thanks! – Bruce Sep 23 '11 at 19:50
  • 3
    That did make it break, thanks again. I don't feel too bad about it, since the Koans haven't even introduced me to the concept of 'blocks' yet. – Bruce Sep 23 '11 at 20:13
  • 1
    (ruby noob here) so as we have already made the change to use a variable, why don't we just use (assert_equal expected, hash) but rather use (assert_equal true, expected == hash)? – Ege Özcan Apr 13 '12 at 08:58
  • 2
    that answer is wrong. Koans and OP, would not write code as above. If it was going to be literal, it would look as follows: `assert_equal true, { :one => "eins", :two => "dos" } == hash` – skrobul Mar 01 '13 at 00:06
  • The last assert doesn't work anymore (yeah it has been 10+years, ruby version 3.0.2p107); What works is: `assert_equal ({ :one => "eins", :two => "dos" }), hash` – user3054986 Nov 20 '22 at 21:20
2

I thought it was more readable, but you can still do something like this:

assert_equal true, { :one => "eins", :two => "dos" } == hash
Matt Kim
  • 759
  • 7
  • 19
  • That has the disadvantage of not displaying the actual values and is more verbose than `assert hash == { :one => "eins", :two => "dos" }`. (I suspect but do not know that the order has to be reversed as I have done.) – PJTraill Aug 17 '17 at 20:46
0

Another test you can use is the following:

assert_equal hash, {:one => "eins", :two => "dos"}

I’ve simply swapped the parameters to assert_equal. In this case Ruby will not throw an exception.

But it still seems a bad solution to me. It’s much more readable using a separate variable and testing a boolean condition.

PJTraill
  • 1,353
  • 12
  • 30
Mich Dart
  • 2,352
  • 5
  • 26
  • 44
  • I'm assuming you actually meant `assert_equal hash, { :one => "eins", :two => "dos" }` – Cincinnati Joe Feb 16 '13 at 21:06
  • For some reason, the signature of the assertion functions is _"(expected, actual)"_. `hash` is _"actual"_, it should not be the first argument. It does not matter if the assertion succeeds but using the arguments in the wrong order produces confusing messages when the assertion fails. – axiac Mar 24 '23 at 07:11
0

I compare the variable expected with the hash, not broke

expected = { :one => 'eins', :two => "dos" }

assert_equal expected, hash
Mike Szyndel
  • 10,461
  • 10
  • 47
  • 63