Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is considered a good spec? Rspec examples for beginners

Tags:

What is considered a solid spec?

This is what I find to be very abstract about testing. I'd be interested in the answer for this on models, controllers and whatever else can be tested. It would be cool to have a spec for a spec, you know what I mean?

A model spec should (in order of priority and relevance):

  1. Test all methods?
  2. Test errors array?
  3. Test CRUD (and how)?
  4. What else?

A controller / view spec should (in order of priority / relevance):

  1. Fill in the blank...
  2. ?

Would be great to expand this list of what a spec should and shouldn't contain.

I'd also like to compile a list of tricks and suggestions as well. For example:

The keyword "should" is sorta redundant.

Example:

this:

it "should be invalid without a firstname"

would be better as:

it "is invalid without a firstname"

Yet another trick, use expect instead of lambda for readability:

lambda { ... }.should be_valid

is more readable as:

expect { ... }.should be_valid

I am compiling a list of helpful articles on getting started and will share those in this post as they come along. Here are some that I'm finding particularly helpful as of now. (Feel free to post yours and I'll tack it on if it seems helpful).

http://everydayrails.com/2012/03/19/testing-series-rspec-models-factory-girl.html http://nelvindriz.tumblr.com/post/835494714/rspec-best-practices

It would be great to have a list of projects where tests are implemented well. Since rspec is so readable (at least that's what everybody says), it would be great to get a list of links to projects that have great specs to read.

"See the Mongoid specs for an example of good specs." -@yfeldblum (see answer below)

Online you'll find a lot of articles describing unrealistic scenarios on how to test basic stuff, but beyond that you're sorta on your own. If I were to write an article on this topic I would just link to my tests (on github for example), then thoroughly annotate one or a few of those specs... this seems like the best way to write an article on rspec, in my opinion. I'd do it myself, but I'm not quite there yet.

If you vote to close this, that's fine, just try to leave a comment or suggestion on where you think this post would belong. Thanks!

like image 333
botbot Avatar asked Aug 07 '12 22:08

botbot


People also ask

What is a spec in RSpec?

A controller spec is an RSpec wrapper for a Rails functional test. (ActionController::TestCase::Behavior). It allows you to simulate a single http request in each example, and then. specify expected outcomes such as: rendered templates.

What RSpec method is used to create an example?

The it Keyword. The word it is another RSpec keyword which is used to define an “Example”. An example is basically a test or a test case. Again, like describe and context, it accepts both class name and string arguments and should be used with a block argument, designated with do/end.

Is RSpec TDD or BDD?

RSpec is a Behavior-Driven Development tool for Ruby programmers. BDD is an approach to software development that combines Test-Driven Development, Domain Driven Design and Acceptance Test-Driven Planning. RSpec helps you do the TDD part of that equation, focusing on the documentation and design aspects of TDD.

How do I run a specific spec test?

File & Directory Names Running tests by their file or directory names is the most familiar way to run tests with RSpec. RSpec can take a file name or directory name and run the file or the contents of the directory. So you can do: rspec spec/jobs to run the tests found in the jobs directory.


2 Answers

This is actually a good question because when I started out with test cases, I wasn't sure what is considered a good test case. Here are a few things which you can follow. This list is not mine; but compiled from a few sources plus some of my additions.

Describe methods

While describing methods, it is a good practice actually describe your method like: describe "#admin?" etc. "." is a prefix for class method and "#" is a prefix for instance methods.

One assert per test case

Make sure that you have just one assertion per test case. This makes sure that your test cases are clean and easy to understand; which is the point of test cases, isn't it? :)

Avoid saving data to db

You can dynamically build objects to and avoid saving data to db. Although you can clean up the db before each test case, "not saving" will speed up test cases in a big way.

@user.build(:something) instead of @user.create(:something)

Edge and Invalid cases

This is not specific to Rspec but it is important to make sure edge cases are covered in testing. This helps greatly later on when your project grows and it gets easy to maintain.

contexting

I, personally, like this a lot in Rspec and I in fact overuse contexts a bit. Using contexts with conditions helps in compartmentalizing your test cases. Here's an example:

# Avoid
it "should have 200 status code if user is logged in" do
  response.should respond_with 200
end
it "should have 401 status code if user is not logged in" do
  response.should respond_with 401
end

# Use
context "when user is logged in" do
  it { should respond_with 200 }
end
context "when user is logged out" do
  it { should respond_with 401 }
end

Using subject

When you have lots of test cases which are related to the same thing, you can use subject() to make sure you don't repeat yourself.

# Avoid
it { assigns(:user).should be_valid }
it { assigns(:user).should_not be_dumb }
it { assigns(:user).should be_awesome }

# Use
subject { assigns("user") }
it { should be_valid }
it { should_not be_dumb }
it { should be_awesome }

Here are a few things that I try to follow when I write test cases. I'm sure there are a lot more things which can improve Rspec test cases. But this should be enough to get started and write awesome test cases.

like image 106
sandeep Avatar answered Oct 03 '22 23:10

sandeep


See the Mongoid specs for an example of good specs.

  • Have exactly one assertion per example. Do not assert two things in the same example. An example is the block passed to it, its, or specify.
like image 42
yfeldblum Avatar answered Oct 03 '22 21:10

yfeldblum