TDD Basics : Test First Programming

Objective


  • To learn about Test First Programming

Discussion


Let's write a simple calculator program driven by test. What statements can you make about the calculator program that is true? How about :

  • It should add given two numbers

Steps


Step 1

Let's write a specification for this statement. Create a file called calculator_spec.rb with the following contents:

describe Calculator do
  it 'should add given two numbers' 
end

The describe is a RSpec method. In this case, we are describing the behavior of the Calculator class. We are expressing the requirement in the method called it that takes a string as it's argument.

Step 2

Go to the directory where the spec file resides and run the test like this:

$rspec calculator_spec.rb --color --format documentation

This test fails.

Step 3

Define Calculator class at the top of the calculator_spec.rb file with the code shown below:

class Calculator
end

describe Calculator do
  it 'should add given two numbers' 
end

You now see a pending spec. This is because you have not written the test yet.

Step 4

Let's write the test as follows:

class Calculator
end

describe Calculator do
  it 'should add given two numbers' do
    calculator = Calculator.new

    result = calculator.add(1,2)

    expect(result).to eq(3)
  end
end

The describe() is a method that takes the class name as its argument. The test is written inside the do-end block of the it method. The it() method takes a string argument. This string argument is called the doc string and describes the scenario we are testing.

We first create an instance of the Calculator class. The second step is invoking the method add(x, y) to calculate sum of two numbers. The third step is checking if the result is the same as we expect. In this step, we have converted the statement that is true to an assertion. The expect() method is the assertion in rspec. It takes an argument that needs to be verified for correctness.

Step 5

Follow the step 2 instructions to run the test again. This test fails because you have not defined the add(x,y) method.

Step 6

Define the add method to the class as follows:

class Calculator
  def add(x,y)

  end
end

describe Calculator do
  # The code here is same as before.
end

Step 7

Follow the step 2 instructions to run the test again. We now have a test that is failing for the right reason. Failing for the right reason means that the test will fail to satisfy the requirements instead of syntax mistakes, missing require statements etc.

Step 8

Change the add to return : x + y. Now the test passes.

Step 9

You can now move the Calculator class to its own file called calculator.rb.

Step 10

Add

require_relative 'calculator'

to the top of the calculator_spec.rb. So the complete code listing for calculator.rb looks like this:

require_relative 'calculator'

class Calculator
  def add(x,y)
    x + y 
  end
end

Step 11

Run the test again. It should now pass.

Summary


In this article we took little baby steps. We wrote the test first. Initial error messages were related to setting up the environment. Once you get past that, you can make the test fail for the right reason. Then you implement the code to make the test pass. Once you get to green you can cleanup the test and the production code. This is called as refactoring. We will discuss more about refactoring in another article.

Q&A

Why do we need to make the test fail for the right reason?

Test does not have a test to prove its correctness. The correctness of the test is done manually, just once by making sure that it fails for the right reason. Strive to make the test so simple that it does not require a test.

Why did we define the Calculator class in the same file as the test?

We did that for convenience, we were able to see all the code at once. You don't have to have them in the same file. You could have split panes in your IDE showing both files so that it is easy to write code.

Exercises


  1. Write specs for the following statements:

    • It should subtract given two numbers
      • It should multiply given two numbers
      • It should divide given two numbers
  2. Write specs for edge cases such as invalid input, division by 0 etc.

  3. Create a .rspec file with the following contents

--color
--format documentation

Now you can run the specs without giving it any options like this:

rspec calculator_spec.rb

What do you see as the output in the terminal?


Related Articles


Create your own user feedback survey