Slide 1

Slide 1 text

TDD in Ruby on Rails 1.9.3 3.2 www.ict4g.org

Slide 2

Slide 2 text

“..is an evolutionary approach to development which combines test-first development where you write a test before you write just enough production code to fulfill that test and refactoring.” http://www.agiledata.org/essays/tdd.html Test Driven Development www.ict4g.org

Slide 3

Slide 3 text

TDD Schema http://blog.drorhelper.com/2010/12/why-you-fail-with-tdd.html www.ict4g.org

Slide 4

Slide 4 text

Refactor TDD Schema Write code to make test
 pass Write a
 failing test Red - Green - Refactor process in TDD www.ict4g.org

Slide 5

Slide 5 text

In RoR we can test: • Models • Controllers • Views • Routes • Helpers • Mailers • API www.ict4g.org

Slide 6

Slide 6 text

• Models • Controllers • Views • Routes • Helpers • Mailers • API A User should have firstname and lastname. The user password should contain at least 5 characters. www.ict4g.org In RoR we can test:

Slide 7

Slide 7 text

• Models • Controllers • Views • Routes • Helpers • Mailers • API After the registration, a new user should redirect to the index page. After logout, a user should see the message “Goodbye!”. www.ict4g.org In RoR we can test:

Slide 8

Slide 8 text

• Models • Controllers • Views • Routes • Helpers • Mailers • API If I write values such as “/home” or “/root” in the address bar of the browser, I should redirect to the homepage. www.ict4g.org In RoR we can test:

Slide 9

Slide 9 text

“By default, every Rails application has three environments: development, test, and production. The database for each one of them is configured in config/database.yml.” www.ict4g.org

Slide 10

Slide 10 text

Rails creates a test folder for you as soon as you create a Rails project. www.ict4g.org rails g scaffold users name:string surname:string email:string

Slide 11

Slide 11 text

require 'test_helper' ! class UserTest < ActiveSupport::TestCase test "the truth" do assert true end end test/unit/user_test.rb Unit Tests A test in ruby is a method www.ict4g.org

Slide 12

Slide 12 text

An assertion (refutation) is a line of code that evaluates an object (or expression) for expected results. assertions/refutations www.ict4g.org

Slide 13

Slide 13 text

assert (test, message = nil) assert_not_nil (test, message = nil) assert_equal (expected, actual, message = nil) assert_difference (expression, difference = 1, message = nil, &block) assert_nil (object, message = nil) assert_raise (*args, &block) assert_not_equal (expected, actual, message = nil) Assertions refute (test, message = nil) refute_equal (expected, actual, message = nil) refute_match (pattern, string, message = nil) refute_nil (object, message = nil) refute_empty(object, message = nil) refute_includes(collection, object, message = nil) Refutations www.ict4g.org

Slide 14

Slide 14 text

require 'test_helper' ! class UsersControllerTest < ActionController::TestCase setup do @user = users(:one) end ! test "should get new" do get :new assert_response :success end ! test "should create user" do assert_difference('User.count') do post :create, user: { email: @user.email, name: @user.name, surname: @user.surname } end assert_redirected_to user_path(assigns(:user)) end ! test "should show user" do get :show, id: @user assert_response :success end ! test "should get edit" do get :edit, id: @user assert_response :success end ! test "should update user" do put :update, id: @user, user: { email: @user.email, name: @user.name, surname: @user.surname } assert_redirected_to user_path(assigns(:user)) end ! test "should destroy user" do assert_difference('User.count', -1) do delete :destroy, id: @user end assert_redirected_to users_path end end www.ict4g.org one: name: MyString surname: MyString email: MyString ! two: name: MyString surname: MyString email: MyString test/fixtures/users.yml test/functional/users_controller_test.rb

Slide 15

Slide 15 text

A test could contains multiple assertions/refutations (bad practice). assertions/refutations Suppose I have 2 assertions. If the first assert fails I have no clue what is the state of the 2nd assertion. www.ict4g.org

Slide 16

Slide 16 text

require 'test_helper' ! class UserTest < ActiveSupport::TestCase test "should not save user without name" do user = User.new assert !user.save # refute user.save end end $ rake test test/unit/user_test.rb test_should_not_save_user_without_name F ! Finished tests in 0.044632s, 22.4054 tests/s, 22.4054 assertions/s. ! 1) Failure: test_should_not_save_user_without_name(UserTest) [test/unit/user_test.rb:6]: Failed assertion, no message given. ! 1 tests, 1 assertions, 1 failures, 0 errors, 0 skips 1 2 TDD Step by step www.ict4g.org

Slide 17

Slide 17 text

$ rake test test/unit/user_test.rb test_should_not_save_user_without_name . Finished tests in 0.047721s, 20.9551 tests/s, 20.9551 assertions/s. 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips TDD Step by step 3 4 class User < ActiveRecord::Base validates :name, presence: true end www.ict4g.org

Slide 18

Slide 18 text

rake test test/functional/user_controller_test.rb ! # Running tests: ! F…..F……………………………………………… [ … ] ….. (other dots)…..(and dots again)…. ! Finished tests in 0.188464s, 37.1424 tests/s, 47.7545 assertions/s. ! 1) Failure: test_should_create_user(UsersControllerTest) [/Users/…/test/functional/users_controller_test.rb:20]: "User.count" didn't change by 1. <3> expected but was <2>. ! 2) Failure: test_should_update_user(UsersControllerTest) [/Users/…/test/functional/users_controller_test.rb:39]: Expected response to be a <:redirect>, but was <200> ! 7 tests, 9 assertions, 2 failures, 0 errors, 0 skips www.ict4g.org www.ict4g.org

Slide 19

Slide 19 text

RSpec “RSpec is a great tool in the behavior-driven development (BDD) process of writing human readable specifications that direct and validate the development of your application.” www.ict4g.org

Slide 20

Slide 20 text

rails g rspec:scaffold user --color
 --format documentation rails g rspec:install www.ict4g.org

Slide 21

Slide 21 text

FactoryGirl & Faker www.ict4g.org

Slide 22

Slide 22 text

require 'faker' ! FactoryGirl.define do ! ! # INVALID USER factory :user do |user| sequence(:email) {|n| "user-#{n}@example.com" } user.name { Faker::Name.first_name } user.phone { Faker::PhoneNumber.phone_number } user.password { "password" } user.password_confirmation { "password" } user.addresses { |a| [a.association(:address)] } end ! # COLLECTOR USER factory :collector, parent: :user do |user| sequence(:email) {|n| "collector-#{n}@example.com" } user.role { "collector" } end ! # SUPPLIER USER factory :supplier, parent: :user do |user| sequence(:email) {|n| "supplier-#{n}@example.com" } user.role { "supplier" } end ! end www.ict4g.org

Slide 23

Slide 23 text

require 'spec_helper' ! describe User do ! # VALID USER ! it "Should create a user with name, surname, email and password" do u = FactoryGirl.create(:user) u.should be_valid end ! # WITHOUT SOME ATTRIBUTES ! it "Should not create a user without name" do u = FactoryGirl.build(:user, name: nil) u.should_not be_valid # assert !u.save or refute u.save end ! end Come back to RSpec www.ict4g.org spec/models/user_spec.rb

Slide 24

Slide 24 text

spec/models/user_spec.rb require 'spec_helper' ! describe User do ! # VALID USER ! it "Should create a user with name, surname, email and password" do u = FactoryGirl.create(:user) u.should be_valid end ! # WITHOUT SOME ATTRIBUTES ! it "Should not create a user without name" do u = FactoryGirl.build(:user, name: nil) u.should_not be_valid end ! it "Should not create a user without surname" do u = FactoryGirl.build(:user, surname: nil) u.should_not be_valid end ! it "Should not create a user without username" do u = FactoryGirl.build(:user, username: nil) u.should_not be_valid end ! it "Should not create a user without email" do u = FactoryGirl.build(:user, email: nil) u.should_not be_valid end ! describe "Testing instance methods" do ! it "full_name method should returns full name" do user = FactoryGirl.build(:user) user.full_name.should eq [user.name, user.surname].join(" ") end end end www.ict4g.org

Slide 25

Slide 25 text

describe User do ! # WITHOUT SOME ATTRIBUTES ! it "Should not create a user without name" do u = FactoryGirl.build(:user, name: nil) u.should_not be_valid end ! it "Should not create a user without surname" do u = FactoryGirl.build(:user, surname: nil) u.should_not be_valid end ! it "Should not create a user without username" do u = FactoryGirl.build(:user, username: nil) u.should_not be_valid end ! it "Should not create a user without email" do u = FactoryGirl.build(:user, email: nil) u.should_not be_valid end end describe User do ! # WITHOUT SOME ATTRIBUTES %w(name surname username email).each do |attr| context "with a nil #{attr}" do it "should not create a valid user" do FactoryGirl.build(:user, attr => nil ).should_not be_valid end end end www.ict4g.org

Slide 26

Slide 26 text

require "spec_helper" ! describe UsersController do ! describe "routing" do ! it "routes to #index" do get("/users").should route_to("users#index") end ! it "routes to #show" do get("/users/1").should route_to("users#show", :id => "1") end ! it "routes to #edit" do get("/users/1/edit").should route_to("users#edit", :id => "1") end ! it "routes to #create" do post("/users").should route_to("users#create") end ! it "routes to #update" do put("/users/1").should route_to("users#update", :id => "1") end ! it "routes to #destroy" do delete("/users/1").should route_to("users#destroy", :id => "1") end ! end ! end Test routes www.ict4g.org

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Capybara “Capybara helps you test web applications by simulating how a real user would interact with your app.” www.ict4g.org http://jnicklas.github.io/capybara/

Slide 29

Slide 29 text

Capybara actions click_link(‘id-of-link’) click_link('Link Text’) ! click_button('Save') click_on('Link Text') click_on('Button Text’) ! fill_in 'First Name', :with => 'John' fill_in 'Password', :with => ‘Password' ! choose ('A Radio Button') check ('A Checkbox') uncheck ('A Checkbox') select 'Option', :from => 'Select Box’ ! visit('http://www.google.com') www.ict4g.org

Slide 30

Slide 30 text

page.has_selector?('table tr') page.has_css?('table tr.foo') page.has_content?(‘foo') ! page.should have_selector('table tr') page.should have_css('table tr.foo') page.should have_content('foo') find_field('First Name').value find_link('Hello').visible? find_button('Send').click ! find("#overlay").find("h1").click ! find('#navigation').click_link('Home') Capybara matchers Capybara finders www.ict4g.org

Slide 31

Slide 31 text

describe "the signin process" do ! before :each do FactoryGirl.create(:email => '[email protected]', :password => 'password') end ! it "signs me in" do visit '/sessions/new' within("#session") do fill_in 'Login', :with => '[email protected]' fill_in 'Password', :with => 'password' end click_link 'Sign in' expect(page).to have_content 'Success' end ! end Capybara with RSpec www.ict4g.org

Slide 32

Slide 32 text

Cucumber www.ict4g.org

Slide 33

Slide 33 text

www.ict4g.org

Slide 34

Slide 34 text

www.ict4g.org Feature file Step definitions file

Slide 35

Slide 35 text

A feature usually contains a list of scenarios. You can write whatever you want up until the first scenario, which starts with the word Scenario on a new line. ! Every scenario consists of a list of steps, which must start with one of the keywords Given, When, Then, But or And.
 Cucumber treats them all the same, but you shouldn’t. Features www.ict4g.org

Slide 36

Slide 36 text

Feature: Login ! I want to login to bring the food as supplier @javascript Scenario: successful login as a supplier Given there exists [email protected] And I am on the landing page When I sign in as [email protected] Then I should be on the home page And I should see "Offers" And I should see "New Offer" www.ict4g.org

Slide 37

Slide 37 text

Feature: User sign in ! @javascript Scenario: successful sign in as a supplier Given I am on the landing page When I sign in as … ! @javascript Scenario: successful sign in as a collector Given I am on the landing page When I sign in as … ! @javascript Scenario: successful sign in as a manager Given I am on the landing page When I sign in as … www.ict4g.org

Slide 38

Slide 38 text

Feature: User sign in ! Background: Given I am on the landing page ! @javascript Scenario: successful sign in as a supplier When I sign in as … ! @javascript Scenario: successful sign in as a collector When I sign in as … ! @javascript Scenario: successful sign in as a manager When I sign in as … www.ict4g.org

Slide 39

Slide 39 text

When I sign in as [email protected] ? www.ict4g.org

Slide 40

Slide 40 text

Step definitions Given /^(?:|I )am on (.+)$/ do |page_name| visit path_to(page_name) end ! When /^(?:|I )follow "([^"]*)"$/ do |link| click_link(link) end ! When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value| fill_in(field, :with => value) end ! # Examples: # # Given I am signed in as [email protected] # Given I am logged in as [email protected] # When I sign in as [email protected] # When I log in as [email protected] ! Given /^I (?:am signed in|sign in|am logged in|log in) as ([\w]+[\w-]*[\w\d](?:@example.com))$/ do |mail| @current_user = User.find_by_email(mail) @current_user.should_not be_nil ! steps %{ Given I am on the landing page When I follow "Login" within the menu And I fill in "Email" with "#{mail}" And I fill in "Password" with "password" Then I press "Sign in" within the modal popup } end Capybara gem Capybara gem Capybara gem RSpec gem www.ict4g.org

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Demo www.ict4g.org

Slide 43

Slide 43 text

1.http://everydayrails.com/2012/03/12/testing-series-intro.html 2.http://everydayrails.com/2012/03/12/testing-series-rspec-setup.html 3.http://everydayrails.com/2012/03/19/testing-series-rspec-models-factory-girl.html 4.http://everydayrails.com/2012/04/07/testing-series-rspec-controllers.html 5.http://everydayrails.com/2012/04/24/testing-series-rspec-requests.html How I learned to test my Rails applications Rails Tutorial 1.http://guides.rubyonrails.org/testing.html Links Rspec Guidelines & Best Practices 1.http://betterspecs.org/ Others 1.http://robots.thoughtbot.com/tags/testing www.ict4g.org