Basic Testing in Ruby: Using RSpec to Build a Simple Calculator
Test Driven Development is an essential component of the Software Development Life Cycle. As such, it’s helpful to know some basics regarding automated testing options for your programming language of choice. Automated testing is extremely efficient, saving both time and money in the process.
In Ruby, one of the most commonly used testing libraries is RSpec, which will be the focus of this blog. We’re going to build a basic Calculator
class and test various functions of it using RSpec.
To begin, be sure that you have the rspec
gem installed. Then, in your directory of choice, create a folder called RSpec
.
From this directory, you will want to create two additional directories: lib
and spec
. Traditionally speaking, test code will live in a separate folder from the code it’s actually testing. Within lib
, create a ruby file called calculator.rb
, and within spec create a ruby file called calculator_spec.rb
.
Let’s write our initial test first. In TDD, this is also common practice, particularly when unit testing new features. We want to ensure that each feature operates the way it’s supposed to as we add it to our code.
There are three keywords that are extremely beneficial to any basic Rspec test: describe
, context
, and it
.
Let’s build our first test to see how these apply.
In spec/calculator_spec.rb
:
require “calculator”describe Calculator do
context “Given two numbers” do
it “can add the numbers using the add method” do
calc = Calculator.new
x = 13
y = 5
expect(calc.add(x, y)).to eq(18)
end
end
end
Notice that we use describe
to qualify what we are testing, in this case, the class.
The keyword context
provides just that, a context via which we plan to test the item described. It commonly refers to the input that will be provided.
The section that begins with the it
keyword highlights what we expect the output to be. Notice here that we also define the variables we use and provide our expectation for what the test case should yield.
In addition, notice some of the other methods and keywords provided by the RSpec library:
expect().to
: Here we pass in what we plan to evaluate. In this case, we call the add
method on the new instance of the Calculator
class we just created, passing in two values to ensure they are added together properly.
eq()
: Here, we provide the value we expect to be rendered by whatever we provided in expect().to
We’ll also need to require the file that our Calculator
class is written in, which you can see is taken care of at the top of the file above.
To run tests, use the command rspec
in your terminal. You’ll also need to specify the file to run the tests from. If you’re still in the RSpec directory in your terminal, this can be done by running rspec spec/calculator_spec.rb
Running this command yields the following:
NameError: uninitialized constant Calculator
Even though this is an error, this is good news! It means that our test file is already beginning to communicate information to us. In this case, the class Calculator
is not being recognized…because we haven’t written it yet!
Let’s build out the initial class:
class Calculator
end
And now run our tests.
Calculator Given two numbers can add the numbers using the add method
Failure/Error: expect(calc.add(x, y)).to eq(18) NoMethodError: undefined method `add’ for # <Calculator:0x00007f7f963e3718>
Now we’re seeing much more here. Notice how the content about the failure/error is derived from what we wrote after describe, context, and it.
And our error is clear. We don’t have a method yet called add in our Calculator class. Let’s add it.
class Calculator
def add
end
end
And run our tests:
Calculator Given two numbers can add the numbers using the add method
Failure/Error: def add end ArgumentError: wrong number of arguments (given 2, expected 0)
The error here is also quite specific. Our tests are expecting to pass two arguments, and our current method as we’ve written it allows for zero. Let’s change that.
class Calculator
def add (x, y)
end
end
And run our tests:
Calculator Given two numbers can add the numbers using the add method
Failure/Error: expect(calc.add(x, y)).to eq(18) expected: 18 got: nil (compared using ==)
So now we’re actually able to run the test in full and compare answers. And we can see that we’re getting nil
because our function isn’t returning anything else. Let’s now build the complete function.
class Calculator
def add (x, y)
x + y
end
end
And run our tests:
1 example, 0 failures
Excellent! We got the tests to pass!
Try writing tests and building methods for the subtract
, multiply
, divide
, and modulo
operators. (Recall the answer that you will get by default utilizing division of two integers in Ruby.)
Hopefully you built out your tests first.
In spec/calculator_spec.rb
:
require “calculator”describe Calculator do
context “Given two numbers” do
it “can add the numbers using the add method” do
calc = Calculator.new
x = 13
y = 5
expect(calc.add(x, y)).to eq(18)
end it “can subtract the numbers using the subtract method” do
calc = Calculator.new
x = 13
y = 5
expect(calc.subtract(x, y)).to eq(8)
end it “can multiply the numbers using the multiply method” do
calc = Calculator.new
x = 13
y = 5
expect(calc.multiply(x, y)).to eq(65)
end it “can divide the numbers using the divide method” do
calc = Calculator.new
x = 13
y = 5
expect(calc.divide(x, y)).to eq(2)
end it “can provide the remainder when dividing two numbers using the modulo method” do
calc = Calculator.new
x = 13
y = 5
expect(calc.modulo(x, y)).to eq(3)
end
end
end
followed by the class in lib/calculator.rb
:
class Calculator
def add(x, y)
x + y
end def subtract(x, y)
x — y
end def multiply(x, y)
x * y
end def divide(x, y)
x / y
end def modulo(x, y)
x % y
end
end
And when we run the tests:
5 examples, 0 failures
Happy coding and testing!