Testing with RSpec (RubyDay 2011)

51
Simone Carletti [email protected] twitter: @weppos Testing with RSpec 2011 Monday, June 20, 2011

description

The slides of my "Testing with RSpec" talk at RubyDay 2011.

Transcript of Testing with RSpec (RubyDay 2011)

Page 1: Testing with RSpec (RubyDay 2011)

Simone [email protected]

twitter: @weppos

Testing with RSpec

2011

Monday, June 20, 2011

Page 2: Testing with RSpec (RubyDay 2011)

Me.about(:robodomain)

Monday, June 20, 2011

Page 3: Testing with RSpec (RubyDay 2011)

Me.about(:ifad)

Monday, June 20, 2011

Page 4: Testing with RSpec (RubyDay 2011)

describe RSpec, "Agenda"

Monday, June 20, 2011

Page 5: Testing with RSpec (RubyDay 2011)

Monday, June 20, 2011

Page 6: Testing with RSpec (RubyDay 2011)

Monday, June 20, 2011

Page 7: Testing with RSpec (RubyDay 2011)

Testing

Monday, June 20, 2011

Page 8: Testing with RSpec (RubyDay 2011)

TDD seems to be applicable in various domains and can

significantly reduce the defect density of developed

software without significant productivity reduction of the

development team.

http://www.infoq.com/news/2009/03/TDD-Improves-

Quality

Monday, June 20, 2011

Page 9: Testing with RSpec (RubyDay 2011)

The pre-release defect density of the four products,

measured as defects per thousand lines of code,

decreased between 40% and 90% relative to the

projects that did not use TDD. The teams' management

reported subjectively a 15–35% increase in initial

development time for the teams using TDD, though the

teams agreed that this was offset by reduced

maintenance costs.

Monday, June 20, 2011

Page 10: Testing with RSpec (RubyDay 2011)

Monday, June 20, 2011

Page 11: Testing with RSpec (RubyDay 2011)

$ rspec

http://relishapp.com/rspec

https://github.com/rspec

Monday, June 20, 2011

Page 12: Testing with RSpec (RubyDay 2011)

Monday, June 20, 2011

Page 13: Testing with RSpec (RubyDay 2011)

describe RSpec, "Features"

Monday, June 20, 2011

Page 14: Testing with RSpec (RubyDay 2011)

Readabilitydescribe Whois::Client do describe "#initialize" do it "accepts a timeout setting with a value in seconds" do klass.new(:timeout => 100).timeout.should == 100 end

it "accepts a timeout setting with a nil value" do klass.new(:timeout => nil).timeout.should be_nil end end

describe "#query" do it "detects email" do expect { klass.new.query("[email protected]") }.to raise_error(Whois::ServerNotSupported) end endend

Monday, June 20, 2011

Page 15: Testing with RSpec (RubyDay 2011)

Readabilitydescribe Whois::Client do describe "#initialize" do it "accepts a timeout setting with a value in seconds" do klass.new(:timeout => 100).timeout.should == 100 end

it "accepts a timeout setting with a nil value" do klass.new(:timeout => nil).timeout.should be_nil end end

describe "#query" do it "detects email" do expect { klass.new.query("[email protected]") }.to raise_error(Whois::ServerNotSupported) end endend

Monday, June 20, 2011

Page 16: Testing with RSpec (RubyDay 2011)

Isolationdescribe UsersController do context "when logged as administrator" do before(:each) do log_in_as @admin = Factory(:user, :username => "admin") end

context "with a bunch of users" do before(:each) { @users = 3.times.map { Factory(:user) } }

describe "GET index" end

context "with no users" do describe "GET new" describe "POST create" end

describe "with a user" do before(:each) { @user = Factory(:user) }

describe "GET show" end endend

Monday, June 20, 2011

Page 17: Testing with RSpec (RubyDay 2011)

Extensibledescribe 9 do it "should be a multiple of 3" do (9 % 3).should == 0 endend

# vs

RSpec::Matchers.define :be_a_multiple_of do |expected| match do |actual| actual % expected == 0 endend

describe 9 do it "should be a multiple of 3" do 9.should be_a_multiple_of(3) endend

Monday, June 20, 2011

Page 18: Testing with RSpec (RubyDay 2011)

describe RSpec, "Syntax"

Monday, June 20, 2011

Page 19: Testing with RSpec (RubyDay 2011)

Basic Exampledescribe String do describe "#upcase" do it "returns the original string converted to uppercase" do "hello".upcase.should == "HELLO" end

it "returns a String" do "hello".upcase.should be_a(String) end

it "does not change the original string" do string = "hello" string.upcase string.should_not == "HELLO" end endend

Monday, June 20, 2011

Page 20: Testing with RSpec (RubyDay 2011)

Basic Exampledescribe String do describe "#upcase" do it "returns the original string converted to uppercase" do "hello".upcase.should == "HELLO" end

it "returns a String" do "hello".upcase.should be_a(String) end

it "does not change the original string" do string = "hello" string.upcase string.should_not == "HELLO" end endend

Monday, June 20, 2011

Page 21: Testing with RSpec (RubyDay 2011)

context / describedescribe "something" do context "in one context" do it "does one thing" do end end

context "in another context" do it "does another thing" do end endend

Monday, June 20, 2011

Page 22: Testing with RSpec (RubyDay 2011)

before / afterdescribe "before / after" do before(:each) {} before(:all) {} before(:suite) {}

after(:each) {} after(:all) {} after(:suite) {}end

# Before and after blocks are called in the following order:# # before suite# before all# before each# after each# after all# after suite

Monday, June 20, 2011

Page 23: Testing with RSpec (RubyDay 2011)

before / afterdescribe "before / after" do before(:each) do @hash = {} end

it "does something" do @hash[:key] = "value" @hash[:key].should_not be_empty endend

Monday, June 20, 2011

Page 24: Testing with RSpec (RubyDay 2011)

let$count = 0describe "let" do let(:count) { $count += 1 }

it "memoizes the value" do count.should == 1 count.should == 1 end

it "is not cached across examples" do count.should == 2 endend

Monday, June 20, 2011

Page 25: Testing with RSpec (RubyDay 2011)

Implicit subjectdescribe Array do describe "when first created" do it "should be empty" do subject.should eq([]) end endend

Monday, June 20, 2011

Page 26: Testing with RSpec (RubyDay 2011)

subjectdescribe Array do subject { [1,2,3] }

describe "with some elements" do it "should have the prescribed elements" do subject.should == [1,2,3] end endend

Monday, June 20, 2011

Page 27: Testing with RSpec (RubyDay 2011)

expectdescribe Integer do describe "#/" do it "raises ZeroDivisionError when divisor is 0" do lambda do 1 / 0 end.should raise_error(ZeroDivisionError) end endend

# vs

describe Integer do describe "#/" do it "raises ZeroDivisionError when divisor is 0" do expect { 1 / 0 }.to raise_error(ZeroDivisionError) end endend

Monday, June 20, 2011

Page 28: Testing with RSpec (RubyDay 2011)

Shared Behaviorsshared_examples "a collection" do let(:collection) { described_class.new([7, 2, 4]) }

context "initialized with 3 items" do it "says it has three items" do collection.size.should eq(3) end end

describe "#include?" do context "with an an item that is in the collection" do it "returns true" do collection.include?(7).should be_true end end

context "with an an item that is not in the collection" do it "returns false" do collection.include?(9).should be_false end end endend

Monday, June 20, 2011

Page 29: Testing with RSpec (RubyDay 2011)

Shared Behaviorsdescribe Array do it_behaves_like "a collection"end

describe Set do it_behaves_like "a collection"end

Monday, June 20, 2011

Page 30: Testing with RSpec (RubyDay 2011)

pendingdescribe Hash do it "adds a key" do { :key => "value" }[:key].should == "value" end

it "does something unknown"

it "does something buggy" do pending "This method is buggy" endend

describe Integer do before(:each) { pending }

it "computes 1 + 1" do (1 + 1).should == 2 end

it "computes 1 - 1" do (1 - 1).should == 0 endend

Monday, June 20, 2011

Page 31: Testing with RSpec (RubyDay 2011)

pendingdescribe Hash do it "adds a key" do { :key => "value" }[:key].should == "value" end

it "does something unknown"

it "does something buggy" do pending "This method is buggy" endend

describe Integer do before(:each) { pending }

it "computes 1 + 1" do (1 + 1).should == 2 end

it "computes 1 - 1" do (1 - 1).should == 0 endend

Monday, June 20, 2011

Page 32: Testing with RSpec (RubyDay 2011)

pendingdescribe "an example" do xit "is pending using xit" do true.should be(true) endend

describe "an example" do it "checks something" do (3+4).should == 7 end pending do "string".reverse.should == "gnirts" endend

Monday, June 20, 2011

Page 33: Testing with RSpec (RubyDay 2011)

Metadatadescribe "something", :this => { :is => :arbitrary } do it "does something", :and => "so is this" do # ... endend

RSpec.configure do |c| c.filter_run_excluding :ruby => lambda {|version| !(RUBY_VERSION.to_s =~ /^#{version.to_s}/) }end describe "something" do it "does something", :ruby => 1.8 do # .... end it "does something", :ruby => 1.9 do # .... endend

Monday, June 20, 2011

Page 34: Testing with RSpec (RubyDay 2011)

MetadataRSpec.configure do |c| c.filter_run :focus => trueend

describe "something", :focus => true do it "does something" do # .... endend

RSpec.configure do |c| c.filter_run_excluding :slow => trueend

describe "something", :slow => true do it "does something" do # .... endend

Monday, June 20, 2011

Page 35: Testing with RSpec (RubyDay 2011)

describe RSpec, "Integration"

Monday, June 20, 2011

Page 36: Testing with RSpec (RubyDay 2011)

RSpec

Monday, June 20, 2011

Page 37: Testing with RSpec (RubyDay 2011)

describe AccountsController do describe "GET show" do before(:each) do get :show end

it { should respond_with :success } it { should render_template "accounts/show" }

it "assigns user" do assigns(:user).should == @user end endend

RSpec# Gemfilegroup :development, :test do gem 'rspec-rails', '~> 2.6.0'end

spec folder

Monday, June 20, 2011

Page 38: Testing with RSpec (RubyDay 2011)

RSpecRSpec.configure do |config| config.include Rack::Test::Methodsend

describe Tremonti::Application do def app Tremonti::Application end

describe "/" do it "should respond with 200" do get "/" last_response.should be_ok last_response.body.should == "Hello from RoboFinance!" end endend

rack-test

Monday, June 20, 2011

Page 39: Testing with RSpec (RubyDay 2011)

RSpec MochaRR

RSpec.configure do |config|

# == Mock Framework # # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: # config.mock_with :mocha # config.mock_with :flexmock # config.mock_with :rr

end

Monday, June 20, 2011

Page 40: Testing with RSpec (RubyDay 2011)

RSpec Factoriesdescribe BillingCharge do subject { Factory.build(:billing_charge) }

describe "associations" do it { should belong_to(:user) } end

describe "validations" do it "is valid with factory" do Factory.build(:billing_charge).should be_valid end

it { should validate_presence_of(:user_id) }

it { should validate_format_of(:period).with('2010-02') } it { should validate_format_of(:period).not_with('201002') } it { should validate_format_of(:period).not_with('2010') } endend

Monday, June 20, 2011

Page 41: Testing with RSpec (RubyDay 2011)

describe RSpec, "Best Practices"

Monday, June 20, 2011

Page 42: Testing with RSpec (RubyDay 2011)

describe vs contextdescribe ".guess" do it "recognizes tld" do s = Whois::Server.guess(".com") s.should be_a(Whois::Server::Adapters::Base) s.type.should == :tld end

context "when the input is a tld" do it "returns a IANA adapter" do Whois::Server.guess(".com").should == Whois::Server.factory(:tld, ".", "whois.iana.org") end end

context "when the input is a domain" do it "lookups definitions and returns the adapter" do Whois::Server.guess("example.test").should == Whois::Server.factory(:tld, ".test", "whois.test") end endend

Monday, June 20, 2011

Page 43: Testing with RSpec (RubyDay 2011)

it vs specifydescribe User do before do @user = User.new :username => 'weppos' end

it "is not an administrator" do @user.should_not be_admin endend

# vs.

describe User do let(:user) do User.new :username => 'weppos' end

specify do user.should_not be_admin endend

Monday, June 20, 2011

Page 44: Testing with RSpec (RubyDay 2011)

shoulddescribe "#order_price" do it "should be a Money" do # ... end

it "should return nil when amount is blank" do # ... endend

# vs

describe "#order_price" do it "is a Money" do # ... end

it "returns nil when amount is blank" do # ... endend

Monday, June 20, 2011

Page 45: Testing with RSpec (RubyDay 2011)

context vs itdescribe Hash, "#size" do it "returns 0 when the Hash is empty" do end

it "returns the number of elements when the Hash is not empty" do endend

# vs

describe Hash, "#size" do context "when the Hash is empty" do it "returns 0" do end end

context "when the Hash is not empty" do it "returns the number of elements" do end endend

Monday, June 20, 2011

Page 46: Testing with RSpec (RubyDay 2011)

Instance vs Class methodsdescribe Time do describe ".parse" do it "converts given string into a Time" do Time.parse('2010-06-12').should == Time.mktime(2010, 06, 12) end end

describe "#to_i" do it "returns the timestamp corresponding to the Time object" do t = Time.mktime(2010, 06, 12) t.to_i.should == 1276293600 end endend

Monday, June 20, 2011

Page 47: Testing with RSpec (RubyDay 2011)

spec_helper.rb & /support

Monday, June 20, 2011

Page 48: Testing with RSpec (RubyDay 2011)

Demo Time

Monday, June 20, 2011

Page 49: Testing with RSpec (RubyDay 2011)

Choose the right tool...

Monday, June 20, 2011

Page 50: Testing with RSpec (RubyDay 2011)

... and Test!

Monday, June 20, 2011

Page 51: Testing with RSpec (RubyDay 2011)

Thanks!

Monday, June 20, 2011