Basic Testing in Ruby: Using RSpec to Build a Simple Calculator

Steven Kandow
The Startup
Published in
4 min readNov 11, 2020
Testing Our 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!

--

--