Slide 1

Slide 1 text

Rémi Prévost — ConFoo 2013 RSpec: natural behavior testing for Rails applications

Slide 2

Slide 2 text

Rémi Prévost Freelance Web Developer

Slide 3

Slide 3 text

• RSpec • RSpec + Rails

Slide 4

Slide 4 text

“ RSpec is a Behaviour-Driven Development tool for Ruby programmers ”

Slide 5

Slide 5 text

• Test for behavior not end results • Natural language Principles

Slide 6

Slide 6 text

Get Started Let’s do it live!

Slide 7

Slide 7 text

• Expectations • Helpers • Mocks (rspec-mocks) Features

Slide 8

Slide 8 text

Expectations Features • Test the behavior of objects or blocks • Objects should or should_not have a certain behavior • We expect blocks to trigger a certain behavior

Slide 9

Slide 9 text

"foo".should eql "foo" # "foo" == "foo" Array.new.should be_an_instance_of(Array) # Array.new.instance_of?(Array) "foo".should_not respond_to(:to_a) # "foo".respond_to?(:to_a) [1, 2, 3].should have(3).items # [1, 2, 3].size == 3

Slide 10

Slide 10 text

[1, 2, 3].should_not be_empty # [1, 2, 3].empty? { foo: "bar" }.should have_key(:foo) # { foo: "bar" }.has_key?(:foo)

Slide 11

Slide 11 text

expect { 42/0 }.to raise_error(ZeroDivisionError) # &block.call rescue ZeroDivisionError items = [1, 2, 3, 4] expect { items.clear }.to change{ items.size }.from(4).to(0) # &expectation.call == 4 # &block.call # &expectation.call == 0

Slide 12

Slide 12 text

Helpers Features • Subjects • Let • Hooks • Contexts

Slide 13

Slide 13 text

Subjects Features • Helpers • Avoid repetitive code

Slide 14

Slide 14 text

describe Post do it("should not be published") do Post.new.should_not be_published? end it("should have a default author") do Post.new.author.should eql "remi" end end class Post < OpenStruct def published? self.published == true end def author self.author || "remi" end end

Slide 15

Slide 15 text

describe Post do subject { Post.new } it { should_not be_published? } its(:author) { should eql "remi" } end class Post < OpenStruct def published? self.published == true end def author self.author || "remi" end end

Slide 16

Slide 16 text

describe Post do it { should_not be_published? } its(:author) { should eql "remi" } end class Post < OpenStruct def published? self.published == true end def author self.author || "remi" end end

Slide 17

Slide 17 text

describe Post do subject { Post.new(author: "jack") } it { should_not be_published? } its(:author) { should eql "jack" } end class Post < OpenStruct def published? self.published == true end def author self.author end end

Slide 18

Slide 18 text

Let Features • Helpers • Lazy-evaluated blocks • Evaluated once for each example

Slide 19

Slide 19 text

describe Post do subject { Post.new(author: user) } let(:user) { User.new(first_name: "Rémi") } its(:author_name) { should eql user.first_name } end class Post < OpenStruct def author_name self.author.first_name end end

Slide 20

Slide 20 text

Hooks Features • Helpers • Before + after • :each, :all, :suite

Slide 21

Slide 21 text

describe Post do before :all do puts "Running tests for Post..." end before :each do ActionMailer::Base.deliveries.clear DatabaseCleaner.clear end it { should_not be_published } its(:author) { should be_nil } end

Slide 22

Slide 22 text

Contexts Features • Helpers • Groups of examples • Shared subject, lets & hooks

Slide 23

Slide 23 text

describe Post do describe :initialize do subject { Post.new(parameters) } context "with empty parameters" do let(:parameters) { {} } it { should_not be_valid? } end context "with valid parameters" do let(:parameters) { { title: "Hello world." } } it { should be_valid? } end end end

Slide 24

Slide 24 text

Mocks Features • Method stubbing • Message expectations

Slide 25

Slide 25 text

describe Post do subject { Post.new(:author_id => 4) } describe :author do before do a = OpenStruct.new(full_name: "Rémi Prévost") Author.stubs(:find).and_return(a) end its(:author) { should eql "Rémi Prévost" } end end class Post < OpenStruct def author Author.find(self.author_id).full_name end end

Slide 26

Slide 26 text

describe Post do subject { Post.new(:author_id => 4) } describe :author do before do a = OpenStruct.new(full_name: "Rémi Prévost") Author.should_receive(:find).with(4).and_return(a) end its(:author) { should eql "Rémi Prévost" } end end class Post < OpenStruct def author Author.find(self.author_id).full_name end end

Slide 27

Slide 27 text

• RSpec • RSpec + Rails

Slide 28

Slide 28 text

• Get Started • Models (unit) • Controllers + Views (integration) RSpec + Rails

Slide 29

Slide 29 text

Let’s do it live! RSpec + Rails

Slide 30

Slide 30 text

Thank you! Comments? Questions? @remi