TDD

What is TDD - Test Driven Development

TDD is an extension of the agile philosphy, which also includes a way to ensure that your application will run the way you think it will.

The way that this is accomplished is with software tests. A set of code that runs verification tests against the application you write.

TDD specifically is a process that builds your app and writes those tests where the test is written before you write your app code.

Practitioners of TDD feel that the process helps them to think about the featrues of their app in a more holistic way, and that it prevents bugs.

Learning Objectives

  • Understand the RSPEC testing library
  • Pass a simple set of ruby class tests
  • Understand the TDD process
  • Write a new class within the TDD process
  • Understand the rails TDD setup

RSPEC Testing library

The main tool we will be using is the RSPEC testing library. This is the tool that runs the verifications (tests) we write.

A simple example looks like this:

it "adds 2 and 2 together" do
  expect(2 + 2).to eq(4)
end

This example is a basic demonstration of what a test does. It simply verifies the output of some piece of code.

We will be using this to test that our code does what we think it should do.

RSPEC Setup

Gemfile

source "https://rubygems.org"

gem 'rspec'

Install it

bundle install

Create a class file:

touch calculator.rb
class Calculator
  attr_accessor :sum
end

Create the testing files:

rspec --init

(checkout what's inside spec/spec_helper.rb)

touch spec/calculator_spec.rb
require 'calculator'

RSpec.describe Calculator, "#score" do
  it "sums the pin count" do
    calc = Calculator.new
    calc.sum = 2
    expect(calc.sum).to eq(2)
  end
end

Run these files:

rspec

Testing with RSPEC

The point of testing is simply to make sure that some representative test cases work properly, and as you continue to code, that they still work.

calc.add(2,2)
expect(calc.sum).to eq(4)
  • you don't need to cover evey single possible case, only some representative cases and most logical cases - e.g., what if the numbers are negative, what if it's zero, what if it's very large
  • test that errors are well handled - does your entire program crash when given a certain input?
  • what are the main funcionalities of your class? How do you run them and what is the output? It could help someone to understand your code to look at what tests you write.

TDD Process

We have been talking about tests that simply verify the behavior of your code. TDD is the process for writing code that begins with a test, reversing the process we have been talking about.

TDD is closely linked with agile in the sense that it is a well defined process that has distinct stages of progression for your code.

The base unit of TDD is a feature- this means one complete unit of functionality (not neccessarily a feature that the user uses). This could be given to you by the scrum master / product manager or come out of a user story, but generally comes out of some user requirement. This means that you know what the behavior of the feature is before you begin work on the code.

For example, I already know that my Calculator class will be able to add numbers together before I decide exactly how to implement that. I understand from a high level what the inputs need to be and what the outputs need to be.

When I begin the TDD process I will be writing a test that exactly specifies a representative input and output.

Only after I am done writing the test to I begin writing my code.

Exercise

https://github.com/wdi-sg/rspecalculator

TDD / Testing in Rails

All of these examples we've seen have been for ruby classes. When you are a back-end developer it can be fairly easy to write code that matches up with your tests.

In a lot of other situations though, testing can be a difficult proposition. What if your class relies on an outside API (twitter, facebook, etc.) - what if it relies on many other classes? How do you test when something takes too long?

For all of these scenarios there are testing strategies, but it's quite rare for tests to cover all of these possible cases within an app. If you did this you would spend more time working on your tests than working on your app.

Most tests are a compromise of what is testable and what is deemed "safe" or non-mission critial code. You will spend more time writing careful tests for the core of an app.

Some of the libraries you are likely to encounter in a rails app are:

End-to-end Testing

One of the high-level strategies for testing an app is called end-to-end, or acceptance testing. Here, we try to actually run the app as a user, using simulated actions in the browser.

The library that is used to write these browser tests is Capybara.

End-to-end testing is considered the last line of defense against bugs.

When TDD is done in the context of rails it usually begins with a user story and an end-to-end test.

Example:

As a farmer I want to be able to calculate my current total harvest so that I can plan my day.

Or

As a user I want to be able to sign in so that I can see by bank balance.

You would then write a test that tests this set of functionality.

it "signs me in" do

  visit '/sessions/new'

  within("#session") do
    fill_in 'Email', with: 'user@example.com'
    fill_in 'Password', with: 'password'
  end

  click_button 'Sign in'
  expect(page).to have_content 'Success'
end

Run the test, and when it fails begin writing the functionality that will allow the test to pass.

Exercise

Setup capybara in rails: From: https://github.com/teamcapybara/capybara

Your Gemfile:

group :development, :test do
  gem 'rspec-rails', '~> 3.7'
end

Add development group to capybara gemfile stuff

group :development, :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15', '< 4.0'
  gem 'selenium-webdriver'
  # Easy installation and use of chromedriver to run system tests with Chrome
  gem 'chromedriver-helper'
end
bundle install

Generate the default rspec rails files:

rails generate rspec:install

Add capybara inside of spec/rails_helper.rb

require 'rspec/rails'
require 'capybara/rspec'
Capybara.default_driver = :selenium_chrome

Check that it works:

bundle exec rspec

Create your first feature spec:

mkdir spec/features
touch spec/features/homepage_spec.rb
require 'rails_helper'

describe "the homepage", type: :feature do
  it "renders homepage" do
    visit '/'
  end
end

Run it:

bundle exec rspec

This test should pass- the browser should be able to visit the root route.

In a TDD workflow let's add a test we know will fail. Add this after visit:

expect(page).to have_content 'Success'

Run the test again.

Write the code that will pass the test.

results matching ""

    No results matching ""