Some random gotchas I had lately when working with RSpec that may help you out in avoiding mistakes and DRY up your specs:

1. Understand the difference between before(:each) and before(:all)

The short story: if you don’t understand the difference always use before (:each).

The long story is the before(:each) block runs before every spec in a group and is cleaned up right after(the transaction is rolled back) whereas the before(:all) block runs ONCE before all specs in a group, HOWEVER it is not rolled back! that means the effects of the before(:all) block on the database will remain between specs . This is usually highly unwanted since you want clean fixtures data between specs. It can cause surprising test failures especially since tests are run in random order (sometimes your test suite will pass, sometimes it won’t). Due to this reason I’d recommend to stick to before(:each) if you’re just starting with RSpec.

2. Use describe and context to group and DRY common specs

Context and describe blocks are awesome since they make for more readable specs and allow you to group common setup code to be shared for all specs in the block.

To demonstrate this let’s say we are testing our PurchasesController in our e-commerce website. We have 2 specs for the controller create method and in both cases our user is unsigned. The content of the specs themselves is not really important for this discussion.

You can see that several things can be improved: the common setup code (signing out the user) is repeated in both specs, and despite sharing common functionality there is no way to tell these specs are related (both relate to unsigned user context).

We improve this by:

(a) creating a context called “Unsigned”

(b) creating a describe block for the create method.

Describe works exactly the same as context but is meant to describe a functionality (like a controller’s method — create) while context should refer to a state within that functionality (like an unsigned user).

Hopefully it’s clear why this is better: I really like that the describe and context blocks already explain what is going on : we are testing a controller’s create method and specifically an unsigned user functionality. By using before blocks inside the context we can run common set up code for all specs (in this case signing out the user). Moreover, our spec names became super small (“is redirected to login”) since they are already described by the context and describe block: I feel this is easier to reason about for people reading your specs, and eventually for you. And finally, it allows us to create structure in our test suite and remain consistent.

3. Stop using allow_any_instance_of for mocking

allow_any_instance_of and it’s step sister expect_any_instance_of are an RSpec way to mock methods in instances. While quite handy, they are alas considered legacy and discouraged .

Let’s say we have a GithubReposController’s index method, which calls a method to fetch popular repos.

Now when we want to test it, we would want to mock the HTTP call to fetch popular repos (if it’s unclear to you why I suggest you read more on mocking).

Since we have no control over the creation of GithubClient, it’s not quite clear how can we mock it? allow_any_instance_of looks like a great candidate:

While this is fine, let’s rewrite the spec without using allow_any_instance_of and using doubles instead:

While a bit less concise we are at least not using a legacy RSpec feature! (Thanks to Sergio for providing this solution)

This is just scratching the surface of RSspec but hopefully it will help some of you to write more readable and maintainable specs!