Upload
ratan-sebastian
View
2.939
Download
1
Tags:
Embed Size (px)
DESCRIPTION
BDD with RSpec.
Citation preview
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” [email protected] ==
‘something’end
end
The Syntax
describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” [email protected] ==
‘something’end
end
EXAMPLE
The Syntax
describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” [email protected] ==
‘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” [email protected] ==
‘something’end
end
The Syntax
describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” [email protected] ==
‘something’end
end
The Syntax
describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” [email protected] ==
‘something’end
end
The Syntax
describe “Unit#something” dobefore(:each) do@unit= Unit.new(params)endit “should return something” [email protected] ==
‘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!!
Links
http://blog.dannorth.net/introducing-bdd/ http://benpryor.com/blog/2007/01/16/state-
based-vs-interaction-based-unit-testing/
http://rspec.info http://rspec.rubyforge.org/rspec/1.2.6/ Why Rspec
? [http://www.ruby-forum.com/topic/184933]
Full List of expectation definition options http://asciicasts.com/episodes/157-rspec-m
atchers-macros