# Objective

• To practice Canonical Test Structure, Given, When, Then

# Discussion

According to the dictionary, the term canonical is defined as:

``````Mathematics : relating to a general rule or standard formula.
``````

In our case, the following three steps is a standard forumula for writing any test:

``````Step 1 - Given : Precondition. The System is in a known state.
Step 2 - When  : Exercise the System Under Test (SUT)
Step 3 - Then  : Postcondition. Check the outcome is as expected.
``````

# Steps

## Step 1

Create a file stack_spec.rb with the following contents:

``````require_relative 'stack'

describe Stack do
it 'should push a given item' do
stack = Stack.new

stack.push(1)

stack.size.should == 1
end

it 'should pop from the stack' do
stack = Stack.new
stack.push(2)

result = stack.pop

result.should == 2
stack.size.should == 0
end
end
``````

We have two specs that describe the behavior of push and pop operations of Stack.

## Step 2

Create a file stack.rb with a simple implementation that can push and pop as follows:

``````class Stack
def initialize
@elements = []
end

def push(item)
@elements << item
end

def   pop
@elements.pop
end

def size
@elements.size
end
end
``````

## Step 3

Run the specs.

``````\$rspec stack_spec.rb
``````

You should see them all pass.

# Discussion

• What is the given condition?
• How do I exercise the system under test?
• How do I verify the outcome?

The answers to these questions will help you write the test. These questions correspond to each of the step in the Canonical Test Structure.

For example, if you have a class called Car, you need to have fuel in order to drive the car. The given condition in this case is that is has fuel. The drive is the behavior you are testing so you invoke drive() on the instance of a car in order to exercise the system under test. When you drive you expect to travel. So, you can verify the outcome by checking the distance traveled for a given amount of time and average speed.

# Identifying Given, When, Then

Here is an example of how to identify Given, When, Then in a test. Copy the following givenwhenthen.rb to canonical exercise directory.

``````def Given
yield
end

def When
yield
end

def Then
yield
end
``````

These are just methods in the givenwhenthen.rb file. Do not create a class for givenwhenthen.rb. The following code identifies the three steps for the stack_spec.rb:

``````require_relative 'stack'
require_relative 'given_when_then'

describe Stack do
it 'should push a given item' do
Given { @stack = Stack.new }

When { @stack.push(1) }

Then { @stack.size.should == 1}
end
end
``````

## Step 4

Run the stack_spec.rb. It should pass.

# Discussion

This is an example for State Verification. We check the state of the system after we exercise the SUT for correctness.

# Summary

In this article we used the training wheels givenwhenthen.rb to practice identifying the three steps of the canonical test structure. It is also called as Arrange Act Assert or AAA. These training wheels are not required once you understand the concept.

# Exercises

Identify the Given, When, Then steps for the second spec:

``````it 'should pop from the stack'.
``````

# Q&A

What if the method does many things things that needs to be tested?

Ideally a method should be small and do just one thing. If a method has three steps with different scenarios, then you will write three different specs for each scenario.

What if I want to test push and pop in one test?

The structure of the test is Arrange, Act, Assert. There should be only one Arrange, one Act and one Assert per test. In this case you would have multiple of each of these steps. So it does not follow the best practice.

Why do we need just one AAA in our test?

Because if you had multiple of each of the steps, you would have the state at the end of the first assertion interact with the state at the end of the second assertion. Ideally we want each test to be isolated.

This is discussed in depth in xUnit Test Patterns by Gerard Mesaros. Here is a concise version of his discussion on this topic.

Principle: Verify One Condition per Test

Also known as: Single Condition Test

When one assertion fails, the rest of the test is not executed. This makes it hard to achieve Defect Localization. A single failed assertion will cause the test to stop running and the rest of the test will provide no data on what works and what doesn't.

What is isolation?

Isolation means that the state is clean in the beginning of each test and it cleans up the state at the end of each test. This makes our tests independent. Making tests independent is a good practice. When the tests are independent we can run them in any order and they will pass.

# Ace the Technical Interview

• Easily find the gaps in your knowledge
• Get customized lessons based on where you are
• Take consistent action everyday
• Builtin accountability to keep you on track
• You will solve bigger problems over time
• Get the job of your dreams

#### Take the 30 Day Coding Skills Challenge

Gain confidence to attend the interview

No spam ever. Unsubscribe anytime.