Join Kevin Skoglund for an in-depth discussion in this video Equivalence matchers, part of Ruby: Testing with RSpec.
- In this movie, we'll begin our exploration of the different RSpec Matchers by looking at the most commonly used type: Equivalence Matchers. First, let's review how Ruby handles comparisons of equality. Typically if we have a value, like x = 1, then we can tell Ruby to compare x with something else, in this case, an integer: 1, to see whether they're the same or not. That == sign is a way of testing loose equality between these two things. The reason I say loose equality is because there is some flexibility in there.
For example, if I'm comparing an integer with a floating point number, they're considered close enough, and so == returns true. However, if we're comparing the integer 1 with the string that contains 1, == will see those as not being the same. They're not close enough. So it's loose equality, but it does have to be roughly the same thing. Type does matter to some extent. Ruby also has a variation on this, which is eql?. This is what I call value equality.
It's testing to see whether the two values are the same. So of course eql? sees 1 equal to 1, but it does not see 1 being equal to 1.0. That's a floating point number. It has a different value. Now of course we could convert between them. Now you might say: "Well that's close enough." But that's what the first operator's for. The first operator's the one that says: "Close enough." And of course in this case as well, the string "1" would still not be equal. So take a look at those true true false and true false false over there in the right column to see that the second version is just a little bit stricter than the regular == sign that we use most of the time.
There's a third version that we can look at. And the best way to see that is by using a string. So let's say we have x equal to a string which is just going to be 'Lynda'. We can use our == sign to see if it's equal to the string 'Lynda', and it will tell us it's true, because those are roughly the same thing. Right, the values are the same. And if we use eql?, it'll tell us that that's true, because the values of each of those are the same. But, if we use Ruby's equal? method, with the full word equal all spelled out, then it says false.
They're not the same. And if you haven't dealt with this before, you might be scratching your head and thinking: "Well why is that? "'Lynda' is equal to 'Lynda'?" It's because this equal with a question mark is actually testing for object identity. So this is identity equality that we're checking in this case. The first one is loose equality, the second one is value equality, and the third one is identity equality. If you wanna test this out in IRB, you can actually tell Ruby to tell you the object ID of x, and the object ID of a string that's just 'Lynda'.
And you can see that they have different object IDs. Therefore equal? is going to return false. So keep all three of these in mind because RSpec has matchers that correspond to those three Ruby equality tests. The most common test that you're gonna use in Ruby is that ==, and therefore the most common one that you'll use in RSpec is going to be just eq, that's the matcher name, eq. You can also write it as "be ==", if you prefer. I think eq is more common, so I'm gonna stick with that.
So if we expect something to equal something, then we use just eq. But just like Ruby, there is a slightly stricter version in RSpec as well. If we use eql, that's equivalent to eql? in Ruby. And as you might guess, the strictest one, the object identity test is equal, just like equal? was. See how they work? They correspond, the only catch is that that == becomes eq. The other ones just simply remove ? from the regular Ruby method.
You can also use be in this instance as well. That's a synonym. So if we're expecting something to be something, we're saying that it actually is the same object. So 99 times out of 100, you want eq. But I think it's important to know about all three, because they do sometimes come up, but more importantly because it's really easy for a beginner to use equal thinking that they're actually just doing a ==. Right, it's actually doing something else. So be careful about that. Let's create a spec that uses these as a demonstration.
I'm gonna go into my spec helper, and I'm gonna tell TextMate to create a new file there. And I'm going to make a new spec file which I'm gonna call expectation_matchers_spec.rb. And I'm just gonna put describe 'Expectation 'Matchers' at the top, and a do and end block. Now you may be thinking: "Well wait a minute, we don't have a class "that we're describing." I'm gonna break the rules a little bit here because what I'm gonna do is make a standalone spec file that's going to demonstrate all of the different matchers.
and this will be a great resource for you because then when you wanna know how a matcher works, you can come back to this demo file and look it up, and you'll have an example there right in front of you to help explain it. To start with, I'll paste in a whole bunch of examples that we can take a look at. So, for example, I've got my equivalence matchers. Right, I'm gonna nest that here, and I'll have different ones for each of the different matchers that we're gonna be looking at. Inside equivalence matchers, we're going to have example that says it 'will match loose equality with #eq', and then we've got an example of how that works.
Right, so you can actually see how that works right here, and you can see it here with it works with the 17 and 17.0. Then I'll have another one here that will match value equality using eql, so we can compare whether or not these two things are the same. So it's the same for two strings. You can see with 17 that it's not the same thing. It'll return that it's not equal in that case in order to pass. And then we'll match identity equality using equal. Same thing, we'll see that they're actually different.
It's not equal. Two strings are different. They're stored as different objects in memory. But if we were to set a new variable c to be equal to b, well then that points to the exact same object. So in that case, they are going to be the same. Alright, so now that we've got those specs in there, let's save that file and let's just run it. Let's come back over here, make sure you're in the root of your car project. rspec spec/expectation_matchers_spec.rb. We'll hit return, it'll run our specs, and all three examples passed with 0 failures.
So all of our expectations were true. Every time we had something that we expected to be true, it was true. Every time that we expected something not to be true, it was not true. We'll continue using this expectation_matchers_spec file in the rest of this chapter. If you take nothing else away from this movie, make sure that you understand that eq is the matcher name for when you wanna test if something is roughly equal to something else.
- Installing and configuring RSpec
- Writing and running examples
- Defining expectations using matchers
- Using helper methods, before/after hooks, and shared examples
- Creating test doubles using mocks and stubs
- Testing Ruby on Rails with RSpec
- Putting test-driven development into practice