Top Banner
Straight Up RSpec 3 a neat Ruby BDD tool
72

Straight Up RSpec 3 - a neat Ruby BDD tool

Sep 08, 2014

Download

Technology

gsterndale

Upgrading, going beyond the basics, introducing some elegant features and promoting readability.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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!()