RSpec Tips
 November 12, 2012
RSpec
 Ruby testing framework
 Friendlier alternative to Test::Unit.
RSpec
 Ruby testing framework
 Friendlier alternative to Test::Unit.

 Behavior-driven development
 TDD-based
RSpec
 Ruby testing framework
 Friendlier alternative to Test::Unit.

 Behavior-driven development
 TDD-based

 Syntax resembles natural language
 describe.. it..
RSpec
 Ruby testing framework
 Friendlier alternative to Test::Unit.

 Behavior-driven development
 TDD-based

 Syntax resembles natural language
 describe.. it..

 Good as documentation
 Where BDD shines.
Test Runner
 Database initialization
 $ rake db:create RAILS_ENV=test
 $ rake db:reset RAILS_ENV=test

 Running the test suite
 $ rspec spec

 Configuration
 .rspec
 spec/spec_helper.rb
Test Runner (cont.)
  Example: truncate databases only on startup

  Viewing code coverage
  coverage/index.html

  Auto-testing with Guard
  $ bundle exec guard

  Spork
  $ spork
Test Structure
  Example Groups
    describe
    context
Test Structure
  Example Groups
    describe
    context

  Examples
    it
Test Structure
  Example Groups
    describe
    context

  Examples
    it

  Assertions
    should
    should_not
Test Structure
  Example Groups
    describe
    context

  Examples
    it

  Assertions
    should
    should_not

  BDD w/ Pending Tests
    pending
Test Structure (cont.)
  Matchers
    be_nil, be_true, be_false
    == vs eql
    have_key
    change
    should_receive
    ... etc
Test Structure (cont.)
  Matchers
    be_nil, be_true, be_false
    == vs eql
    have_key
    change
    should_receive
    ... etc

  Custom Matchers (shoulda-matchers)
    should allow_mass_assignment_of :some_attribute
    should have_many(:association).dependent(:destroy)
    should validate_presence_of :first_name
Hooks
 Callbacks used to setup/teardown tests
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
     after :all
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
     after :all
     after :suite
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
     after :all
     after :suite
 RSpec’s default behavior
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
     after :all
     after :suite
 RSpec’s default behavior
     before :suite = Database truncation
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
     after :all
     after :suite
 RSpec’s default behavior
     before :suite = Database truncation
     after :each = Transaction rollback    config.use_transactional_fixtures = true
Hooks
 Callbacks used to setup/teardown tests
 Kinds?
     before :suite
     before :all
     before :each
     around :each
     after :each
     after :all
     after :suite
 RSpec’s default behavior
     before :suite = Database truncation
     after :each = Transaction rollback config.use_transactional_fixtures = true
     The problem with using multiple databases
Subject
 The main object of concern inside an
 example group
 Implicit
 vs.

 Explicit
Subject (cont.)
  should without a receiver

  its shortcut

  Concise + Consistent = DRY (specs as documentation)
  ”One expectation” rule
  Example: Project template before & after
Unit Tests
  Checking piece-by-piece
Unit Tests
  Checking piece-by-piece
  Isolate
Unit Tests
  Checking piece-by-piece
  Isolate
    Design idempotent tests (no database truncation)
Unit Tests
  Checking piece-by-piece
  Isolate
    Design idempotent tests (no database truncation)
    Remove dependencies (openfire)
Unit Tests
  Checking piece-by-piece
  Isolate
    Design idempotent tests (no database truncation)
    Remove dependencies (openfire)
    Narrow down responsibility (template inheritance)
Unit Tests
  Checking piece-by-piece
  Isolate
    Design idempotent tests (no database truncation)
    Remove dependencies (openfire)
    Narrow down responsibility (template inheritance)

  Trust but verify
Unit Tests
  Checking piece-by-piece
  Isolate
    Design idempotent tests (no database truncation)
    Remove dependencies (openfire)
    Narrow down responsibility (template inheritance)

  Trust but verify
    shoulda-matchers
Unit Tests
  Checking piece-by-piece
  Isolate
    Design idempotent tests (no database truncation)
    Remove dependencies (openfire)
    Narrow down responsibility (template inheritance)

  Trust but verify
    shoulda-matchers

    Mock and stub      (omniauth_callbacks_controller_spec.rb)
Integration Tests
  Putting the pieces together and making
  sure they fit
Integration Tests
  Putting the pieces together and making
  sure they fit
  Simulating real users with Capybara
Integration Tests
  Putting the pieces together and making
  sure they fit
  Simulating real users with Capybara
  Mocking authentication
Integration Tests
  Putting the pieces together and making
  sure they fit
  Simulating real users with Capybara
  Mocking authentication
    Devise::TestHelpers (problem with spec controllers bypassing the
    router, problem with lack of direct access to the request variable in integration tests)
Integration Tests
  Putting the pieces together and making
  sure they fit
  Simulating real users with Capybara
  Mocking authentication
    Devise::TestHelpers (problem with spec controllers bypassing the
    router, problem with lack of direct access to the request variable in integration tests)


    Warden::Test::Helpers
Additional Resources
 Pragmatic, The RSpec Book
 http://betterspecs.org
 http://rspec.info
 https://www.relishapp.com/rspec
 https://github.com/bbatsov/ruby-style-guide
 http://mikbe.tk/2011/03/21/mocks-stubs-
 rspec

Rspec Tips

  • 1.
  • 2.
    RSpec Ruby testingframework Friendlier alternative to Test::Unit.
  • 3.
    RSpec Ruby testingframework Friendlier alternative to Test::Unit. Behavior-driven development TDD-based
  • 4.
    RSpec Ruby testingframework Friendlier alternative to Test::Unit. Behavior-driven development TDD-based Syntax resembles natural language describe.. it..
  • 5.
    RSpec Ruby testingframework Friendlier alternative to Test::Unit. Behavior-driven development TDD-based Syntax resembles natural language describe.. it.. Good as documentation Where BDD shines.
  • 6.
    Test Runner Databaseinitialization $ rake db:create RAILS_ENV=test $ rake db:reset RAILS_ENV=test Running the test suite $ rspec spec Configuration .rspec spec/spec_helper.rb
  • 7.
    Test Runner (cont.) Example: truncate databases only on startup Viewing code coverage coverage/index.html Auto-testing with Guard $ bundle exec guard Spork $ spork
  • 8.
    Test Structure Example Groups describe context
  • 9.
    Test Structure Example Groups describe context Examples it
  • 10.
    Test Structure Example Groups describe context Examples it Assertions should should_not
  • 11.
    Test Structure Example Groups describe context Examples it Assertions should should_not BDD w/ Pending Tests pending
  • 12.
    Test Structure (cont.) Matchers be_nil, be_true, be_false == vs eql have_key change should_receive ... etc
  • 13.
    Test Structure (cont.) Matchers be_nil, be_true, be_false == vs eql have_key change should_receive ... etc Custom Matchers (shoulda-matchers) should allow_mass_assignment_of :some_attribute should have_many(:association).dependent(:destroy) should validate_presence_of :first_name
  • 14.
    Hooks Callbacks usedto setup/teardown tests
  • 15.
    Hooks Callbacks usedto setup/teardown tests Kinds?
  • 16.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite
  • 17.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all
  • 18.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each
  • 19.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each
  • 20.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each
  • 21.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each after :all
  • 22.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each after :all after :suite
  • 23.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each after :all after :suite RSpec’s default behavior
  • 24.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each after :all after :suite RSpec’s default behavior before :suite = Database truncation
  • 25.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each after :all after :suite RSpec’s default behavior before :suite = Database truncation after :each = Transaction rollback config.use_transactional_fixtures = true
  • 26.
    Hooks Callbacks usedto setup/teardown tests Kinds? before :suite before :all before :each around :each after :each after :all after :suite RSpec’s default behavior before :suite = Database truncation after :each = Transaction rollback config.use_transactional_fixtures = true The problem with using multiple databases
  • 27.
    Subject The mainobject of concern inside an example group Implicit vs. Explicit
  • 28.
    Subject (cont.) should without a receiver its shortcut Concise + Consistent = DRY (specs as documentation) ”One expectation” rule Example: Project template before & after
  • 29.
    Unit Tests Checking piece-by-piece
  • 30.
    Unit Tests Checking piece-by-piece Isolate
  • 31.
    Unit Tests Checking piece-by-piece Isolate Design idempotent tests (no database truncation)
  • 32.
    Unit Tests Checking piece-by-piece Isolate Design idempotent tests (no database truncation) Remove dependencies (openfire)
  • 33.
    Unit Tests Checking piece-by-piece Isolate Design idempotent tests (no database truncation) Remove dependencies (openfire) Narrow down responsibility (template inheritance)
  • 34.
    Unit Tests Checking piece-by-piece Isolate Design idempotent tests (no database truncation) Remove dependencies (openfire) Narrow down responsibility (template inheritance) Trust but verify
  • 35.
    Unit Tests Checking piece-by-piece Isolate Design idempotent tests (no database truncation) Remove dependencies (openfire) Narrow down responsibility (template inheritance) Trust but verify shoulda-matchers
  • 36.
    Unit Tests Checking piece-by-piece Isolate Design idempotent tests (no database truncation) Remove dependencies (openfire) Narrow down responsibility (template inheritance) Trust but verify shoulda-matchers Mock and stub (omniauth_callbacks_controller_spec.rb)
  • 37.
    Integration Tests Putting the pieces together and making sure they fit
  • 38.
    Integration Tests Putting the pieces together and making sure they fit Simulating real users with Capybara
  • 39.
    Integration Tests Putting the pieces together and making sure they fit Simulating real users with Capybara Mocking authentication
  • 40.
    Integration Tests Putting the pieces together and making sure they fit Simulating real users with Capybara Mocking authentication Devise::TestHelpers (problem with spec controllers bypassing the router, problem with lack of direct access to the request variable in integration tests)
  • 41.
    Integration Tests Putting the pieces together and making sure they fit Simulating real users with Capybara Mocking authentication Devise::TestHelpers (problem with spec controllers bypassing the router, problem with lack of direct access to the request variable in integration tests) Warden::Test::Helpers
  • 42.
    Additional Resources Pragmatic,The RSpec Book http://betterspecs.org http://rspec.info https://www.relishapp.com/rspec https://github.com/bbatsov/ruby-style-guide http://mikbe.tk/2011/03/21/mocks-stubs- rspec