RSpec is a domain-specific language (DSL) testing tool that was created to test ruby code. The idea is to write tests first and then write just enough code to pass the tests and then follow with refactoring. Since RSpec is a behavior driven development (BDD) test tool it focuses on describing what an application does and whether it follows a specification. RSpec is meant to be really easy to read. Adopting a test driven approach will make you a better developer because it forces you to think critically about the program and its features. Today I am going to show you how easy it is to get started writing tests using RSpec.
First we are going to start by making sure that RSpec is installed. This is very simple, just install the RSpec gem with this command.
$ gem install rspec
Now we have rspec installed and we can generate some configuration files. First create and go into a directory. Then we are going to run a command that will create the configuration files.
$ mkdir rspec\_example
$ cd rspec\_example/
$ rspec --init
This command will create two files, the first is inside a folder named spec called spec_helper.rb and the other is .rspec. Inside this spec folder is where we will be writing our tests. We can start with an easy example. Let’s try to do a greeting program that will take in a name and greet you. First let’s create a ruby file in the main directory and a greeting spec file inside the spec folder.
$ touch greeting.rb
$ touch spec/greeting\_spec.rb
In the greeting.rb file we are going to create a greeting class that will be initialized with a name.
class Greeting
def initialize(name)
@name = name
end
end
Now by following test driven development lets write a test to implement the greeting. We want the Greeting class to have a method that will greet when called. Lets start building the test skeleton for our greeting_spec.rb.
require './greeting'
RSpec.describe Greeting do
end
First we require ‘./greeting’. In a test file, we are describing the behavior of the class. For RSpec to know what class we are dealing with we have to wrap the test definition with an RSpec.describe block. It is important to know that the name of the class is not mandatory and can be replaced with a string if you would like. The word describe is an RSpec keyword and it is used to describe a “Example Group”, which can be thought of as a collection of tests. For our program we want a method that will give a greeting with a name included. So now we can start describing the method.
require './greeting'
RSpec.describe Greeting do
describe '#greet\_me' do
it 'prints a greeting with the name' do
end
end
end
The ‘it’ keyword is used to define an ‘Example’ which is our test. Just like describe, it accepts a class name or string argument and should be used with a block argument. Inside this block is where we will test the behavior of our program. We want to create a new instance of the Greeting class and call the greet_me method on it. Then we should expect it to output the greeting. Our test will look like this now.
require './greeting'
RSpec.describe Greeting do
describe '#greet\_me' do
it 'prints a greeting with the name' do
greeting = Greeting.new('Ray')
expect(greeting.greet\_me).to eq('Hello Ray')
end
end
end
The expect keyword in RSpec is used to define an ‘Expectation’. This is the step where we check if a certain expectation has been met. The .eq method is referred to as a matcher. When the greet_me method is called and the output is equal to ‘Hello Ray’ the test will pass. The syntax is very easy to read and almost reads exactly as plain English. Go ahead an run the rspec command on the terminal and you will see something like this.
Failures:
1) Greeting#greet\_me prints a greeting with the name
Failure/Error: expect(greeting.greet\_me).to eq('Hello Ray')
NoMethodError:
undefined method \`greet\_me' for #<Greeting:0x00005639ee5775c8 [@name](http://twitter.com/name "Twitter profile for @name")\="Ray">
# ./spec/greeting\_spec.rb:7:in \`block (3 levels) in <top (required)>'
Finished in 0.00139 seconds (files took 0.06321 seconds to load)
1 example, 1 failure
The test didn’t pass because we don’t have a greet_me method defined. So let’s go step by step and create a method named greet_me in the greeting.rb file.
class Greeting
def initialize(name)
@name = name
end
def greet\_me
end
end
Now that we have the method defined run rspec again and you will notice that the error looks like this.
Failures:
1) Greeting#greet\_me prints a greeting with the name
Failure/Error: expect(greeting.greet\_me).to eq('Hello Ray')
expected: "Hello Ray"
got: nil
(compared using ==)
# ./spec/greeting\_spec.rb:7:in \`block (3 levels) in <top (required)>'
Finished in 0.01522 seconds (files took 0.06191 seconds to load)
1 example, 1 failure
The error tells you that it expects to see “Hello Ray” but instead it got nil. You may be able to see how this feedback loop can be helpful in building your code. Now that we know what the next step is let’s get the test passing. Let’s add this to our code.
class Greeting
def initialize(name)
@name = name
end
def greet\_me
"Hello #{@name}"
end
end
Now when we run RSpec you can see that all of the tests have passed!
Finished in 0.00151 seconds (files took 0.06547 seconds to load)
1 example, 0 failures
Tests are also a great part of documentation. You can run a command that will show you what a method is responsible for. That way if someone is new to the project and wants to know more about the Greeting class they can see how it behaves.
$ rspec --format documentation
Greeting
#greet\_me
prints a greeting with the name
Finished in 0.00095 seconds (files took 0.06487 seconds to load)
1 example, 0 failures
Testing will help you with making sure that your code behaves exactly the way you want it to. This process will also make you a better developer. Experience in RSpec is mentioned in most job offers, so it’s valuable knowledge and may be beneficial for you if you plan to work as a Ruby developer. Have fun writing tests and happy coding! 😎
Top comments (0)