straight up rspec 3 - a neat ruby bdd tool

72
Straight Up RSpec 3 a neat Ruby BDD tool

Upload: gsterndale

Post on 08-Sep-2014

221 views

Category:

Technology


3 download

DESCRIPTION

Upgrading, going beyond the basics, introducing some elegant features and promoting readability.

TRANSCRIPT

Page 1: Straight Up RSpec 3 - a neat Ruby BDD tool

Straight Up RSpec 3a neat Ruby BDD tool

Page 2: Straight Up RSpec 3 - a neat Ruby BDD tool

Organization $0

Running Specs $0

Configuration $0

Refactoring Exercise $0

Other Libraries $0

The Menu

Page 3: Straight Up RSpec 3 - a neat Ruby BDD tool

Organization

Page 4: Straight Up RSpec 3 - a neat Ruby BDD tool

.rspeclib/…spec/spec_helper.rbspec/support/matchers/drink.rbspec/martini_spec.rb

Page 5: Straight Up RSpec 3 - a neat Ruby BDD tool

spec_helper.rb

require 'barkeep'!Dir["#{File.dirname(__FILE__)}/support/**/*.rb"]. each {|file| require file }

spec_helper

Page 6: Straight Up RSpec 3 - a neat Ruby BDD tool

Running Specs

Page 7: Straight Up RSpec 3 - a neat Ruby BDD tool

.rspec

--color--warnings--require spec_helper

.rspec

Page 8: Straight Up RSpec 3 - a neat Ruby BDD tool

.rspec-local

—-format documentation--backtrace

.rspec-local

Page 9: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec spec/martini_spec.rb:15:22

Page 10: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec --format documentation

Page 11: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec --fail-fast

Page 12: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec --tag js:true

Page 13: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec --profile…!Top 10 slowest examples (0.00226 seconds, 57.2% of total time): Martini with a mixer #ingredients should include "vermouth" 0.00058 seconds ./spec/martini_spec.rb:15 InitializeWithAttrsSpec with attributes #pages should eq 123 0.00052 seconds ./spec/initialize_with_attrs_spec.rb:16…

Page 14: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec --order random…Randomized with seed 63958

Page 15: Straight Up RSpec 3 - a neat Ruby BDD tool

$ rspec --order random:63958

Page 16: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Martini" do … it "should have ingredients", :focus do expect(martini).to respond_to(:ingredients) end …end

:focus

Page 17: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Martini" do … fit "should have ingredients" do expect(martini).to respond_to(:ingredients) end …end

fit

Page 18: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Martini" do … it "should have ingredients", :skip do expect(martini).to respond_to(:ingredients) end …end

:skip

Page 19: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Martini" do … xit "should have ingredients" do expect(martini).to respond_to(:ingredients) end …end

xit

Page 20: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Martini" do … pending "should have price" do expect(@martini).to be_pricey end …end

pending

Page 21: Straight Up RSpec 3 - a neat Ruby BDD tool

Configuration

Page 22: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

RSpec.configure do |config| config.include MyMartiniMatchers config.include ModelHelpers, :type => :modelend!!# spec/model/martini_spec.rb!describe Martini, :type => :model do …end

RSpec.configure

Page 23: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

RSpec.configure do |c| c.before(:suite) {} # once c.before(:context) {} # once before each group c.before(:example) {} # once before each example! c.after(:example) {} # once after each example c.after(:context) {} # once after each group c.after(:suite) {} # once! # run before each example of type :model config.before(:example, :type => :model) {}end

RSpec.configure

Page 24: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

RSpec.configure do |c| c.filter_run focus: true c.run_all_when_everything_filtered = trueend!# in any spec filedescribe "thing" do it "does something interesting", :focus do # .... endend

Inclusion

Page 25: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

RSpec.configure do |c| c.exclusion_filter = { :ruby => lambda { |version| !(RUBY_VERSION.to_s =~ /^#{version.to_s}/) }}end!# in any spec filedescribe "something" do it "does something", :ruby => 1.8 do # .... end it "does something", :ruby => 2.1 do # ....

Exclusion

Page 26: Straight Up RSpec 3 - a neat Ruby BDD tool

Barkeepgithub.com/gsterndale/barkeep

an upgrade & refactoring exercise

Page 27: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do before do @martini = Barkeep::Martini.new end it "should have an attribute named booze" do @martini.should respond_to(:booze) @martini.should respond_to(:booze=) end it "should have an attribute named garnish" do @martini.should respond_to(:garnish) @martini.should respond_to(:garnish=) endend

Original Martini 2.X Spec

Page 28: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do before do @martini = Barkeep::Martini.new end it "should have an attribute named booze" do expect(@martini).to respond_to(:booze) expect(@martini).to respond_to(:booze=) end it "should have an attribute named garnish" do expect(@martini).to respond_to(:garnish) expect(@martini).to respond_to(:garnish=) endend

Martini Spec 3.0

Page 29: Straight Up RSpec 3 - a neat Ruby BDD tool

have_attribute.rb

module AttributeMatchers! Spec::Matchers.define :have_attribute do |name| match do |target| getter = name.to_sym setter = (name.to_s + "=").to_sym target.respond_to?(getter) && target.respond_to?(setter) end end!end

Custom Matcher

Page 30: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do include AttributeMatchers before do @martini = Barkeep::Martini.new end it "should have an attribute named booze" do expect(@martini).to have_attribute(:booze) end it "should have an attribute named garnish" do expect(@martini).to have_attribute(:garnish) endend

Custom Matcher

Page 31: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do include AttributeMatchers subject { Barkeep::Martini.new } it "should have an attribute named booze" do expect(subject).to have_attribute(:booze) end it "should have an attribute named garnish" do expect(subject).to have_attribute(:garnish) endend

subject()

Page 32: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do include AttributeMatchers subject(:martini) { Barkeep::Martini.new } it "should have an attribute named booze" do expect(martini).to have_attribute(:booze) end it "should have an attribute named garnish" do expect(martini).to have_attribute(:garnish) endend

Named subject()

Page 33: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do include AttributeMatchers subject { Barkeep::Martini.new } it "should have an attribute named booze" do is_expected.to have_attribute(:booze) end it "should have an attribute named garnish" do is_expected.to have_attribute(:garnish) endend

Implicit subject()

Page 34: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do include AttributeMatchers subject { Barkeep::Martini.new } it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:garnish) }end

DRY Messages

Page 35: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do include AttributeMatchers it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:garnish) }end

Derived subject()

Page 36: Straight Up RSpec 3 - a neat Ruby BDD tool

have_attribute.rb

module AttributeMatchers …end!RSpec.configure do |config| config.include AttributeMatchersend

config.include()

Page 37: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:garnish) }end

config.include()

Page 38: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe "Barkeep::Martini" do before do @martini = Barkeep::Martini.new end it "should have an attribute named booze" do @martini.should respond_to(:booze) @martini.should respond_to(:booze=) end it "should have an attribute named garnish" do @martini.should respond_to(:garnish) @martini.should respond_to(:garnish=) endend

Original Martini 2.X Spec

Page 39: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:garnish) }end

Refactored Martini 3.0 Spec

Page 40: Straight Up RSpec 3 - a neat Ruby BDD tool

whiskey_spec.rb

describe Barkeep::Whiskey do it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:glass) }end

New Whiskey Spec

Page 41: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:glass) } it { is_expected.to have_attribute(:garnish) }end

Additions to Martini Spec

Page 42: Straight Up RSpec 3 - a neat Ruby BDD tool

support/examples/drink.rb

shared_examples_for "a drink" do it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:glass) }end

Shared Example Group

Page 43: Straight Up RSpec 3 - a neat Ruby BDD tool

whiskey_spec.rb

describe Barkeep::Whiskey do it_behaves_like "a drink"end

Whiskey Spec

Page 44: Straight Up RSpec 3 - a neat Ruby BDD tool

whiskey_spec.rb

describe Barkeep::Whiskey do include_examples "a drink"end

Whiskey Spec

Page 45: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it_behaves_like "a drink" it { is_expected.to have_attribute(:garnish) }end

Martini Spec

Page 46: Straight Up RSpec 3 - a neat Ruby BDD tool

support/examples/drink.rb

shared_examples_for "a drink" do |ingredients| it { is_expected.to have_attribute(:booze) } it { is_expected.to have_attribute(:glass) }! describe "#ingredients" do subject { super().ingredients } it { is_expected.to be_a Array } it { is_expected to include *ingredients } endend

Whiskey & Martini #ingredients

Page 47: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it_behaves_like "a drink", "vodka" it { is_expected.to have_attribute(:garnish) }end

Martini Spec

Page 48: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it_behaves_like "a drink" it { is_expected.to have_attribute(:garnish) } it { is_expected.to have_attribute(:mixer) } context "with a mixer" do before do @mixer = 'vermouth' subject.mixer = @mixer end it "should include mixer in ingredients" do expect(subject.ingredients).to include @mixer end end

context()

Page 49: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it_behaves_like "a drink" it { is_expected.to have_attribute(:garnish) } it { is_expected.to have_attribute(:mixer) } context "with a mixer" do let(:mixer) { 'vermouth' } before { subject.mixer = mixer }! it "should include mixer in ingredients" do expect(subject.ingredients).to include mixer end endend

let()

Page 50: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it_behaves_like "a drink" it { is_expected.to have_attribute(:garnish) } it { is_expected.to have_attribute(:mixer) } context "with a mixer" do let(:mixer) { 'vermouth' } before { subject.mixer = mixer }! its(:ingredients) { is_expected.to \ include mixer } endend

its()

Page 51: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini do it_behaves_like "a drink" it { is_expected.to have_attribute(:garnish) } it { is_expected.to have_attribute(:mixer) }end!describe Barkeep::Martini, ".new with mixer" do let(:mixer) { 'vermouth' } subject { Barkeep::Martini.new(mixer: mixer) } its(:ingredients) { is_expected.to include mixer }end

its()

Page 52: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".new with mixer" do let(:mixer) { 'vermouth' } subject { Barkeep::Martini.new(:mixer => mixer) } its(:ingredients) { is_expected.to include mixer } its(:ingredients) { is_expected.to have(1).items }end

have()

Page 53: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".new with mixer" do let(:mixer) { 'vermouth' } subject { Barkeep::Martini.new(:mixer => mixer) } its(:ingredients) { is_expected.to include mixer } it { is_expected.to have(1).ingredients }end

have()

Page 54: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".dirty" do let(:martini) { Barkeep::Martini.dirty } subject { martini.ingredients }! it { is_expected.to include \ 'juice', 'vodka', 'olives', 'vermouth' }! it { is_expected.to contain_exactly \ 'vodka', 'vermouth', 'juice', 'olives' }end

Array Matchers

Page 55: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".dirty" do let(:martini) { Barkeep::Martini.dirty } subject { martini.ingredients }! it { is_expected.to start_with 'vodka' } it { is_expected.to end_with 'olives' }end

Array Matchers

Page 56: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".dirty" do let(:martini) { Barkeep::Martini.dirty } subject { martini.ingredients }! it { is_expected.to all be_a(String) } it { is_expected.to all start_with(/^\w/) }end

Array Matchers

Page 57: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".dirty" do let(:martini) { Barkeep::Martini.dirty } subject { martini.ingredients }! it { is_expected.to all \ be_a(String) & start_with(/^\w/) }end

Compound Matchers

Page 58: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".dirty" do let(:martini) { Barkeep::Martini.dirty } subject { martini.ingredients }! it { is_expected.to match [ start_with(/^\w/), match(/olives?/) ] }end

Composable Matchers

Page 59: Straight Up RSpec 3 - a neat Ruby BDD tool

martini_spec.rb

describe Barkeep::Martini, ".dirty" do let(:martini) { Barkeep::Martini.dirty } subject { martini.ingredients }! it { is_expected.to match [ a_string_starting_with(/^\w/), a_string_matching(/olives?/) ] }end

Composable Matchers

Page 60: Straight Up RSpec 3 - a neat Ruby BDD tool

terminal_spec.rb

describe Terminal, "#printer" do let(:epson) { stub "Espon 5000" } let(:terminal) { Terminal.new(:ip => "1.1.1.1") } subject { terminal.printer }! before do Printer.stub(:by_ip).and_return(epson) end! it { should eq epson }end

RSpec 2.X doubles

Page 61: Straight Up RSpec 3 - a neat Ruby BDD tool

terminal_spec.rb

describe Terminal, "#printer" do let(:epson) { double "Espon 5000" } let(:terminal) { Terminal.new(:ip => "1.1.1.1") } subject { terminal.printer }! before do allow(Printer).to receive_messages(by_ip: epson) end! it { is_expected.to eq epson }end

RSpec 3.0 doubles

Page 62: Straight Up RSpec 3 - a neat Ruby BDD tool

terminal_spec.rb

describe Terminal, "#printer" do let(:epson) { double "Espon 5000" } let(:terminal) { Terminal.new(:ip => "1.1.1.1") } subject { terminal.printer }! before do allow(Printer).to receive_messages(by_ID: epson) end! it { is_expected.to eq epson }end

Double checking™

Page 63: Straight Up RSpec 3 - a neat Ruby BDD tool

terminal_spec.rb

describe Terminal, "#printer" do let(:epson) { stub "Espon 5000" } let(:terminal) { Terminal.new(:ip => "1.1.1.1") } subject { terminal.printer }! before do Printer.should_receive(:by_ip) .with("1.1.1.1").and_return(epson) end! it { should eq epson }end

RSpec 2.X message expectation

Page 64: Straight Up RSpec 3 - a neat Ruby BDD tool

terminal_spec.rb

describe Terminal, "#printer" do let(:epson) { double "Espon 5000" } let(:terminal) { Terminal.new(:ip => "1.1.1.1") } before do allow(Printer).to receive_messages(by_ip: epson) end subject! { terminal.printer }! it { is_expected.to eq epson } it "finds printer by IP" do expect(Printer).to \ have_received(:by_ip).with("1.1.1.1") end

RSpec 3.0 message expectation

Page 65: Straight Up RSpec 3 - a neat Ruby BDD tool

Links

Page 66: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

Its:github.com/rspec/rspec-its!Collection Matchers:github.com/rspec/rspec-collection_matchers!RSpec Rails:github.com/rspec/rspec-rails!ActiveModel mocks:github.com/rspec/rspec-activemodel-mocks

Libraries

Page 67: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

Step-by-step upgrade instructions:relishapp.com/rspec/docs/upgrade!RDoc:rubydoc.info/github/rspec/rspec-expectations!Features as documentation:relishapp.com/rspec

Documentation

Page 68: Straight Up RSpec 3 - a neat Ruby BDD tool

support/configure.rb

Transpec, the RSpec syntax conversion tool:yujinakayama.me/transpec/!Myron Marston’s blog:myronmars.to

Resources

Page 69: Straight Up RSpec 3 - a neat Ruby BDD tool

CHEERS

Page 70: Straight Up RSpec 3 - a neat Ruby BDD tool

spec/user_spec.rb

describe User, ".admin_names" do let(:admin) { User.create!(:admin => true, :first => "Clark", :last => "Kent")} let(:avg_joe) { User.create!(:admin => false, :first => "Joe", :last => "Shmo")} subject { admin_names }! it { should include "Clark Kent" } it { should_not include "Joe Shmo" }end

let() gotcha

Page 71: Straight Up RSpec 3 - a neat Ruby BDD tool

spec/user_spec.rb

describe User, ".admin_names" do let(:admin) { User.create!(:admin => true, :first => "Clark", :last => "Kent")} let(:avg_joe) { User.create!(:admin => false, :first => "Joe", :last => "Shmo")} subject { User.admin_names } before { admin && avg_joe }! it { should include "Clark Kent" } it { should_not include "Joe Shmo" }end

let() work-around

Page 72: Straight Up RSpec 3 - a neat Ruby BDD tool

spec/user_spec.rb

describe User, ".admin_names" do let!(:admin) { User.create!(:admin => true, :first => "Clark", :last => "Kent")} let!(:avg_joe) { User.create!(:admin => false, :first => "Joe", :last => "Shmo")} subject { User.admin_names }! it { should include "Clark Kent" } it { should_not include "Joe Shmo" }end

let!()