---
title: "Stubbles - Stubbing and Doubles innit. \U0001F9D4"
teaser: 'Confession: I''ve always struggled to understand the difference between stubbing
  and doubles...'
tags: testing,rspec,ruby
author: Sami Birnbaum
published_on: 2023-03-10
---

As you start to get more familiar with automated testing, at some point you will likely hear other developers say things like:

"You know you can just stub that method, right?"

"This is a great candidate for a double!"

And at the beginning these things can be confusing to understand. 😕

So let's start by defining each term, followed by their practical use, in specific relation to `rspec` within a `rails` project.

---

### Definitions 📖

One of the tricky things I have seen when these concepts are defined is that they are often defined within the context of testing.

For me, that just adds a layer of complexity.

It is true that these concepts are often used within the context of testing, but they don't have to be.

So let's take a stab _or should I say stub_ 😆 at defining them without talking about tests.

#### Stubbing

Stubbing is just a term for defining a method on an object.

However, it indicates the short-term nature of that method.

If you stub a method on an object, your intention is that it exists for a short period of time and most likely returns a simple hard-coded value.

You may use a stub to define a method that does not exist yet on an object or to override an existing method to get it to return a value you desire.

For example:

```ruby
class Feature
  def self.available?(name)
    # all features are disabled by default
    false
  end
end

puts Feature.available?("user_preference")
# => false

# stub: override the method to return a canned response
def Feature.available?(name)
  true
end

puts Feature.available?("user_preference")
# => true

```

#### Doubles

A double, is simply an object that is a double of another object.

You may be thinking, "but why would you do that?!", but lets put that question to one side for now
just so we can understand the concept in its purest form.

A double of something is just a copy of that thing.

If I have one chocolate and I double that chocolate I now have two of the same chocolate.
We can call the first chocolate the original and the second chocolate a double of the original. yum. 🍫

Great Success!! We made it this far and we haven't talked about tests!

---

### Testing 🧪

Hopefully now that we understand these concepts independent of testing we can talk a little bit about
how they can be helpful tools to use when testing.

#### Stubbing

Sometimes when you are testing a method, the method under test will send a message to another object in order to retrieve some value.

That sounds confusing but look at this example:

```ruby

class EasyMath
  def sum(a,b)
    if SumFeature.available?
      a + b
    end
  end
end
```

The `available?` message is being sent to another class `SumFeature` in order to return the value `true` or `false`.

When we come to test the behaviour of the `sum` method, it would be really useful if we could just worry about
`a + b` without having to be concerned with what the `available?` method does. 

At the end of the day, the `available?` method belongs to the `SumFeature` class and has nothing to do with us over here and we can assume it is tested in the `SumFeature` class where it is defined.

Well thankfully we have a tool in our arsenal called `stubbing` that will allow us to `stub` the `available?` method so it always returns `true`. 

This is great! We can now focus on testing `a + b` whilst relying on `available?` to always return `true`.

Ok, but what does this look like in a test?

```ruby
describe "#sum" do
  it "adds two numbers together and returns the total" do
    easy_math = EasyMath.new
    allow(SumFeature).to receive(:available?).and_return(true)

    total = easy_math.sum(2,2)

    expect(total).to eq(4)
  end
end
```

See that line `allow(SumFeature).to receive(:available?).and_return(true)`?

The `available?` method has now been stubbed out to always return `true`.

No matter how many times you call `SumFeature.available?` in your application code, it will always return `true`.

We did a thing! We stubbed a method! And as you can see it had nothing to do with doubles! 💥

#### Doubles

Ok if you have made it this far, then stay with me as we are nearly there..

Let's take the same example we used above with the `sum` method, but tweak it slightly, to see how we could use a `double`.

```ruby

class EasyMath
  def sum(a,b,user)
    if user.likes_math?
      a + b
    end
  end
end
```

Once again we are sending a message `likes_math?` somewhere else in order to retrieve a value of `true` or `false`.

Similarly we only want to concern ourselves with the behaviour of `a + b` without having to worry about `likes_math?`.

Given what we know so far, we might suggest stubbing the `likes_math?` method in the same way we stubbed `available?`.

`allow(user).to receive(:likes_math?).and_return(true)`

However, whilst a class method like `available?` can be stubbed without the need for a `double`, an instance method does require
a `double` before it can be stubbed. (There are exceptions to this by using `any_instance_of` but it is [not recommended](https://relishapp.com/rspec/rspec-mocks/docs/working-with-legacy-code/any-instance).

In other words we first need to create a `double` of the `user` object before we can stub the `likes_math?` method on it, to
always return `true` for us.

Now hold on one second!! Why am I talking about `stubbing` alongside `doubles`? Didn't I kind of say I didn't want to do that?!

Ok hear me out on this one...

Whilst `stubbing` and `doubles` are completely separate concepts, a `double` is only **meaningful and useful** once you `stub` methods on it.

This is because when you create a `double` you are creating a `double` of that object without any methods on it.

The `double` is just a plain Ruby `Object`.

Therefore, in reality, although `stubbing` is used on its own, when you are using a `double` you will likely need to use `stubbing` as well.

Ok so lets see how the code would look for testing our `sum` method:

```ruby
describe "#sum" do
  it "adds two numbers together and returns the total" do
    easy_math = EasyMath.new
    user_double = double
    allow(user_double).to receive(:likes_math?).and_return(true)

    total = easy_math.sum(2,2,user_double)

    expect(total).to eq(4)
  end
end
```

See how we first create a `double` like this `user_double = double`.

And on the next line we `stub` the `likes_math?` method on to our `double` like this: `allow(user_double).to receive(:likes_math?).and_return(true)`.

It might be helpful to think about it this way:

A `double` is a useful tool to help you to be able to easily `stub`.

---

And that's really all there is to it folks!

But before I go, let's wrap up with some helpful tips.

### Take-Away Tips 🪶

#### Stubbing

- Stubbing has nothing to do with doubles.
- It helps us to force the return value of a method we don't care about in our test because it is tested elsewhere.
- A class method can be stubbed without the need for a double.
- An instance method will need a double (unless you use `any_instance_of`).

#### Doubles

- Doubles are a useful way to create an object that acts as a double of another object.
- The most basic way to create a double in `rspec` is to use the `double` method.
- Another option is to use `instance_double(User)`. This is the same as `double` but will verify that any methods you stub exist on the class you are doubling.
- If you are using
  [`FactoryBot`](https://github.com/thoughtbot/factory_bot_rails) you can use
  [`build_stubbed(:user)`](https://thoughtbot.github.io/factory_bot/ref/build-strategies.html#build_stubbed)
  which will create an `instance_double` but with the methods stubbed out as
  set in the factory. It also has the added advantage of stubbing out
  associated objects and created timestamps.

---

### 🧔
