Effective Rails Testing Practices

Similar documents
Authentication in Rails

Fast, Sexy, and Svelte: Our Kind of Rails Testing. Dan Manges (ThoughtWorks) zak (unemployed)

This user guide covers how existing CSUFEDU Qualtrics account users can migrate their account from the CSUFEDU brand to the Fullerton brand.

Comp 97: Design Document

JBehave Code Generator Manual. Contents: 1) Introduction & Installation 2) Why we need Code Generator. 3) How to generate code with example.

Rails: MVC in action

Courslets, a golf improvement web service. Peter Battaglia

COVENTRY MEDICARE CERTIFICATION TRAINING CENTER

Naviance ID Login Reference Guide

Lecture 8. Validations & Sessions 1 / 41

User Authentication and Session Control

RingBase. Design Specification. March 4, Chandra Krintz CS 189A. Wednesday 6PM. Date March 4, 2014 Mentor Colin Kelley

Here are some figures to consider while answering the following questions.

MVC :: Understanding Views, View Data, and HTML Helpers

Lecture 4. Ruby on Rails 1 / 49

Multitenancy with Rails

Software Engineering 2 (SWT2)

Contents in Detail. Foreword by Xavier Noria

Migration Methods* Column Options. Active Record Supported Types. Add Column. Remove Column. Create Table. Don t Forget to Rake!

MSD 6 Lite. This document will explain how to register and activate your MSD 6 Lite.

Ministry Platform: The Portal

Sign up. Chapter Signup form

Access Guide for New Donor Connect Users

WHO-SEARO HEALTH INFORMATION PLATFORM (HIP) Standard Operating Procedures

Problem: Write HTML would create web page depicted below. Your solution must include the following types of HTML elements (and no other

My First Three Weeks on Rails. Aaron Mulder Chariot Solutions

A Guide to Testing Rails Applications

DRYing Out MVC (ESaaS 5.1)"

Rails Engines. Use Case. The Implementation

my.scouting Tools Create Account

Common Resources v1.0

Module Certification and Testing

Rails: Views and Controllers

NETCONF Client GUI. Client Application Files APPENDIX

Attach2Dynamics User Manual. Attach2Dynamics - User Manual. P a g e 1 of 23

Should you encounter any issues or have questions as you go through this registration process, please send an to:

THE LHH. For New Users. Using a webcam, you can record your responses to standard interview questions and assess your performance.

Demystifying Rails Plugin Development

Multitenancy with Rails - 2nd edition

CITI ACCESS AND DIRECTIONS FOR EXTRAMURAL PERFORMERS NEW USERS

Best Practices Benchmarking Application

WeChat Adobe Campaign Integration - User Guide

Lecture 4. Ruby on Rails 1 / 52

MYCLOUD STORE PARTNER PORTAL USER GUIDE 1

Air Elite Management Guide. World Fuel Services elearning Tool

Entrust PartnerLink Login Instructions

Rails Guide. MVC Architecture. Migrations. Hey, thanks a lot for picking up this guide!

Cheap, Fast, and Good You can have it all with Ruby on Rails

Examples of Cisco APE Scenarios

2016 AHA ANNUAL SURVEY WALK-THROUGH THE 2016 AHA ANNUAL SURVEY ONLINE

CSC4370/6370 Spring/2010 Project 1 Weight: 40% of the final grade for undergraduates, 20% for graduates. Due: May/8th

Online Appointment Request

MyTax.DC.gov User Guide: How to Sign up

1 New TCCH Outlook Web App

Introduction to Ruby on Rails

Web System Development with Ruby on Rails

Databases - Have it your way

STRS OHIO Telework F5 BIG-IP Edge Client for Mac Systems (Imac, Air, Macbook, Mini) User Guide

CS169.1x Lecture 6: Basic Rails" Fall 2012"

Equality and Human Rights Team. A step-by-step guide to logging on to the Electronic Staff Record (ESR) to check and update your demographic details

This tutorial will show you, how to use RSpec to test your code when building applications with Ruby.

Concierge OneSource eprocurement

AAN - Axon. Two Factor Authentication User Manual

Introduction to Ruby on Rails

Magento Survey Extension User Guide

Unit Testing J2EE from JRuby. Evan Light

Ruby on Rails 3. Robert Crida Stuart Corbishley. Clue Technologies

SCHEDULE AN APPOINTMENT

1 Register 2 Take Course 3 Take Test 4 Get Certificate

Validations vs. Filters

Spec-ops Password Reset Enrollment and Usage

Building a Rails Application. Part 2

Elixir and Phoenix. fast, concurrent and explicit. Tobias pragtob.info

Security in Confirmit Software - Individual User Settings

Introduction to Ruby on Rails

Cummins Online Login not 2

This tutorial has been designed for beginners who would like to use the Ruby framework for developing database-backed web applications.

RACK / SSO. and a little bit about the Bundler. Tuesday, December 1, 2009 hello hello

If you ve ordered a (OFFICE SOLUTION) product, you MUST. obtain local connectivity between your devices.

SSH with Globus Auth

PEDStestOnline Authentication and Security

PROFESSIONALISM RUBRIC PORTAL AND DASHBOARDS

A. Getting Started About e-access Enrolling in e-access: Authenticating your account Login... 5

Spock - The Logical Enterprise Testing Tool

Managing WCS User Accounts

How to Register in Ariba - Supplier Information Management System

How to Use Your EV Connect Account

Service Integration course BPMN

Knowledge Base. Release Notes Version 2.0

OCDE Business Applications

Faculty Web Page Management System. Help Getting Started

Please go to to complete the threshold questions. Click Here for the PIMS Users Manual

v ON24/7 Online Support Requests 24/7 Custom Support Advisories Automatic Updates Status Tracking Ticketing System

Mixed Signals Using Fusion s Signals API

Device LinkUP + VIN. Service + Desktop LP Guide RDP

Ramses Documentation. Release. Brandicted

PowerSchool Parent Portal Access - Account Setup Instructions

Quick Start Manual for Mechanical TA

How to Register your Institution with proposalcentral

EasyChair Instructions for Authors

Transcription:

Effective Rails Testing Practices Mike Swieton atomicobject.com

atomicobject.com

2007: 16,000 hours

General testing strategies Integration tests View tests Controller tests Migration tests

Test at a high level: Integration tests Test at a low level: Unit tests

Integration Tests Every user story Every normal error case Load every page Render every partial Submit every form Unit Tests Every class Every method Every edge case Every error case Are comprehensive

Story Driven Development

Understand the user story Create an integration test that represents the story Implement it starting from the view, letting tests drive your development

General testing strategies Integration tests View tests Controller tests Migration tests

should 'be taken to accept the terms of service if the terms have been updated' do now = DateTime.now - 2.seconds ensure_larry_has_accepted_current_tos now ensure_tony_has_accepted_current_tos now with_user(:larry, :password => 'secret') do log_in_to_user_dashboard logout end with_user(:tony, :password => 'secret') do log_in_to_user_dashboard go_to_edit_community_info submit_form do f f.community.terms_of_service = 'these are the new terms' end assert_response :redirect follow_redirect! #...

should 'be taken to accept the terms of service if the terms have been updated' do now = DateTime.now - 2.seconds ensure_larry_has_accepted_current_tos now ensure_tony_has_accepted_current_tos now with_user(:larry, :password => 'secret') do log_in_to_user_dashboard logout end with_user(:tony, :password => 'secret') do log_in_to_user_dashboard go_to_edit_community_info submit_form do f f.community.terms_of_service = 'these are the new terms' end assert_response :redirect follow_redirect! #...

should 'be taken to accept the terms of service if the terms have been updated' do now = DateTime.now - 2.seconds ensure_larry_has_accepted_current_tos now ensure_tony_has_accepted_current_tos now with_user(:larry, :password => http://www.thoughtbot.com/projects/shoulda 'secret') do log_in_to_user_dashboard logout end with_user(:tony, :password => 'secret') do log_in_to_user_dashboard go_to_edit_community_info submit_form do f f.community.terms_of_service = 'these are the new terms' end assert_response :redirect follow_redirect! #... Shoulda

def log_in go_to_login_page see_that_we_are_on_login_page enter_login_and_password end def log_in_to_user_dashboard log_in see_user_dashboard end def see_that_we_are_on_login_page assert_select 'form#f_signin' end def enter_login_and_password submit_form do form form.user.login = @user.login form.user.password = @password end assert_response :redirect #...

def log_in go_to_login_page see_that_we_are_on_login_page enter_login_and_password end def log_in_to_user_dashboard log_in see_user_dashboard end def see_that_we_are_on_login_page http://code.google.com/p/form-test-helper/ assert_select 'form#f_signin' end def enter_login_and_password submit_form do form form.user.login = @user.login form.user.password = @password end assert_response :redirect #... FormTestHelper

General testing strategies Integration tests View tests Controller tests Migration tests

Test every method Test all edge cases To do this, you need small methods

rake stats

+----------------------+-------+ Name LOC/M +----------------------+-------+ Controllers 8 Helpers 10 Models 7 Libraries 6 Components rake stats 0 Finders 9 Presenters 5

+----------------------+-------+ Name LOC/M +----------------------+-------+ +----------------------+-------+ Controllers Name 8 LOC/M Helpers +----------------------+-------+ 10 Models Finder specs 7 14 Libraries Mailer specs 6 3 Components Presenter rake stats specs 0 7 Finders Model specs 9 6 Presenters View specs 5 7 Controller specs 8 Helper specs 4 Library specs 8 Migration tests 17 Integration tests 6 Functional tests 7 Unit tests 6

The Unit Test Toolbox

Mock objects

Mock objects

Mock objects Use RSpec http://rspec.info/documentation/rails/

Built-in RSpec Functional tests Test views Test actions View specs Test views Controller specs Test controllers

Unit Testing Actions

fun_controller.rb def doit assigns[:user] = User.find(14) end fun_controller_spec.rb describe FunController do it "does it" do user = mock_model(user) User.should_receive(:find). with(14). and_return(user) get :doit assigns[:user].should == user end end

Dependency Injection Traditional code SomeHelper.new With injection SomeHelper provided to constructor

Injection http://atomicobjectrb.rubyforge.org/

login_controller.rb class LoginController < ApplicationController inject :landing_page_director, :accessors => true def authenticate if valid_login? redirect_to( @landing_page_director. redirect_user(user)) #...

login_controller.rb class LoginController < ApplicationController inject :landing_page_director, :accessors => true def authenticate if valid_login? redirect_to( @landing_page_director. redirect_user(user)) #...

login_controller.rb class LoginController < ApplicationController inject :landing_page_director, :accessors => true def authenticate if valid_login? redirect_to( @landing_page_director. redirect_user(user)) #...

login_controller_spec.rb it 'redirects valid user to proper landing page' do landing_page_director = create_mock('landing_page_director') @controller.landing_page_director = landing_page_director login_controller.rb landing_page_director.should_receive(:redirect_user). with(@user). class LoginController < ApplicationController and_return('http://foo.com') inject :landing_page_director, :accessors => true def authenticate if valid_login? redirect_to( @landing_page_director. redirect_user(user)) #...

login_controller_spec.rb it 'redirects valid user to proper landing page' do landing_page_director = create_mock('landing_page_director') @controller.landing_page_director = landing_page_director login_controller.rb landing_page_director.should_receive(:redirect_user). with(@user). class LoginController < ApplicationController and_return('http://foo.com') inject :landing_page_director, :accessors => true def authenticate if valid_login? redirect_to( @landing_page_director. redirect_user(user)) #...

Sidebar on Fixtures Good for integration tests Good for good data Not so good for unit tests Prefer mocks - they ll run faster too Don t be afraid to insert new records in integration and unit tests for a specific case

Unit Testing Views

hello.rhtml <div id="username"> Hi, <% @user.name %>! </div> A Simple View Test hello_view_spec.rb describe "a view test" do it "greets the user" do assigns[:user] = stub( :name => "Willy J. Stankifier") render "hello" assert_select "#username", "Willy J. Stankifier".to_regex end end

with_partial.rhtml <div id="craphappens"> <% if @error_message %> <%= render :partial => "shared/error", :locals => { :message => @error_message } %> <% end %> </div> A Test With Mocks with_partial_view_spec.rb describe "a view with a partial" do it "renders the partial" do assigns[:error_message] = "O Snap!" template.expect_render( :partial => "shared/error", :locals => { :message => "O Snap!" }) render "with_partial" assert_select "#craphappens", /O Snap/ end end

General testing strategies Integration tests View tests Controller tests Migration tests

Test them too. Seriously.

Usually developed quickly Run against production data With no or few of your data validations Often perform tricky transformations

Usually developed quickly Run against production data With no or few of your data validations Often perform tricky transformations and you don t have tests for it?!

They re not disposable.

MigrationTestHelper http://migrationtest.rubyforge.org/

Testing All Migrations http://migrationtest.rubyforge.org/

def see_full_schema assert_schema do s s.table :sessions do t t.column :id, :integer t.column :session_id, :string t.column :data, :text t.column :updated_at, :datetime end s.table :users do t t.column :id, :integer t.column :login, :string t.column :salt, :string t.column :password, :string t.column :owner_id, :integer t.column :owner_type, :string t.column :created_at, :datetime t.column :updated_at, :datetime #...

Testing One Migration http://migrationtest.rubyforge.org/

076_munge_the_data_test.rb def test_migration_munge_the_data drop_all_tables migrate :version => 75 # < setup test data > Migrate to any schema version migrate :version => 76 # < test the results > migrate :version => 75 # < test the down migration > end

But I already have a project going!

RSpec on Rails can coexist with existing tests

RSpec on Rails can coexist with existing tests Injection can be added to new code with zero impact

RSpec on Rails can coexist with existing tests Injection can be added to new code with zero impact Migration tests

Put it all together

Use Injection to help you break code into bite-sized bits. Use RSpec to test controllers and views separately. Use integration tests to ensure your applications continues to work. Test migrations with the MigrationTestHelper. http://atomicobject.com

Injection: http://rubyforge.org/projects/atomicobjectrb/ MigrationTestHelper: http://migrationtest.rubyforge.org/ RSpec on Rails http://rspec.info/documentation/rails/ FormTestHelper http://code.google.com/p/form-test-helper/ Shoulda http://www.thoughtbot.com/projects/shoulda http://atomicobject.com