RSpec: What, How and Why

Post on 15-Jan-2015

2.939 views 1 download

Tags:

description

BDD with RSpec.

Transcript of RSpec: What, How and Why

RSpec

The What, How and Why?

WHAT?

What is Rspec?

A BDD Framework for Ruby

What is Rspec?

A BDD Framework for RubyA testing framework that supports BDD

/[T|B]DD/: Just Tests ... Right?

What is BDD

/[T|B]DD/: Just Tests ... Right?

100% Code Coverage is Good.Good Code + 100% Coverage is Better.

Feel Free make whatever you want out of the above picture

Enter BDD

Dan North(ThoughtWorks)

Teaching TDD was hard

TDD needed Direction

The Tools of BDD

Change Of Focus

Interaction-Based Testing

A Ubiquitous Language

Change of Focus

Tests have a tendency of loosing focus of what we’re meant to be building. Too low level.

test_cases.each {|case| case.should add_business_value}

tests which describe domain specific functions => specs

Keeps focus. Gives direction.

Interaction-Based Testing

As opposed to state-based testing

OOP design principles:Object exposes methods which are the only thing

that touch its internal state.

Any change in state requires a method call. SO:Just test that the call is made. Mock out all

neighboring objects.

A true UNIT test.

Is that a Bad thing?<wait for the onslaught>

HOLD ON!

Doesn’t that mean that my tests are tightly coupled with my implementation?

HOW?

How Do I use Rspec (with rails)?

How Do I use Rspec (with rails)?

gem install rspec rspec-rails

How Do I use Rspec (with rails)?

gem install rspec rspec-rails

./script/generate rspec

The Rspec FilesRAILS_ROOT

./specmodels

user_spec.rb

views

controllers

[spec|rcov].opts

helpers

spec_helper.rb

factories

./scriptautospec

spec

A Word about Factories

A easy-to-maintain replacement for fixtures(Finally some code!)

More about creating your own strategies at theend of this presentation

spec_helper.rb

Loaded at the beginning of ever spec file

Put methods that can be used by all specs here.

Examples

The equivalent of a unit test in RSpec

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

EXAMPLE

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

The Syntax

context “Unit#something” dobefore(:each) do

@unit= Unit.new(params)endspecify “should return something” do

@unit.something.should == ‘something’

endend

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

The Syntax

describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” do@unit.something.should ==

‘something’end

end

The mocking/stubbing framework object.stub!(:foo => ‘bar’, :one => 1) object.stub!(:foo).and_return(‘bar’) mock_object= mock/mock_model(Klass,

espectations= {:foo => ‘bar’}) mock_object.foo #=> ‘bar’

Tool for Interaction Testing: mock_object.should_receive(:message).exactly(n

).times.with(params).and_return(val) Each of the methods in that chain take many

different options. Ref: Links Raises error if the message isn’t received

& with the parameters specified & with the correct freq.

Mocks Aren’t StubsStubs provide canned answers to calls made during

the test, usually not responding at all to anything outside what's programmed in for the test. Stubs

may also record information about calls, such as an email gateway stub that remembers the messages

it 'sent', or maybe only how many messages it 'sent'.

Mocks are […] objects pre-programmed with expectations which form a specification of the calls

they are expected to receive.

-Martin Fowler

Functional Tests(Controller Examples)

Isolate controllers from the models(mocks)

Big difference from Rails Functional Testing:

Also isolate it from the views.

Integration is possible with integrate_views

Controller specific Expectations

Response Expectations should be_success should render_template

should be_redirect should redirect_to

response.[assigns|flash|sessions]

Routing Expectations route_for(:controller => …, :action => …).should == /…/…/

params_from(:get,"/hello/world").should ==

{:controller=>"hello” ,:action => "world"}

View Examples

Again<Yawn> Isolation is key.

# examplearticle = mock_model(Article) article.should_receive(:author).and_return("J”)article.should_receive(:text).and_return("this is the text of the article")

assigns[:article] = article assigns[:articles] = [article]# flash and params are also available

# template <% for article in @articles -%> <!-- etc -->

View Specific Expectations

response.should have_tag#examplesresponse.should have_tag('div#interesting_div‘, contents)

# Contents can be Regexp or String

response.should have_tag("input[type=?][checked=?]", 'checkbox', 'checked')

response.should have_tag('ul') do with_tag('li', 'list item 1') with_tag('li', 'list item 2') with_tag('li', 'list item 3')

end

Exercise

My Spec

WHY?

The RSpec Philosophy

Clarity over Cleverness

Completely isolate the unit under test

i.e. Mock Everything

Pros and Cons

Easily understandable tests

True unit tests Interoperability with

other testing frameworks

More descriptive code == more lines of code

Not very DRY Tight coupling of test

and implementation.

Interaction Testing is a Guideline

Not a rule

Depends on what you are testing.

Remember: Usually leads to better OO Design not always

better tests.

Good News

Rspec doesn’t force IBT on you

Write tests that work best for you.

If we’re doing SBT with Rspec.Why not stick to Test::Unit?

OPTIONS

RSpec is versatile. Can do everything that Test::Unit does and then some.

Undoubtedly better for adding new functionality

Why RSpec?

RSpec is not just about RSpec. It's about BDD. It's about encouraging conversation about testing and looking at it in different ways. It's about illuminating the design, specification, collaboration and documentation aspects of tests, and thinking of them as executable examples of behaviour. You can do this all without RSpec, but RSpec aims to help with innovations like:

strings as example names pending examples nested groups for flexible organization should[_not] + matchers (inspired by hamcrest - a java library) one matcher supports both positive and negative expectations improved failure messages flexible/readable/customizable output formats built-in mocking framework plain text scenarios (now in Cucumber)

- David Chelimsky(RSpec lead developer)

More Quotes

The problem I have with TDD is that its mindset takes us in a different direction... a wrong direction. – Dave Astels(RSpec Creator)

Thank You!

Questions.

Pleeeeease!!