SlideShare a Scribd company logo
1 of 38
Download to read offline
Efficient Rails Test-DrivenEfficient Rails Test-Driven
Development — Week 3Development — Week 3
Wolfram ArnoldWolfram Arnold
www.rubyfocus.bizwww.rubyfocus.biz
In collaboration with:In collaboration with:
Sarah Allen, BlazingCloud.netSarah Allen, BlazingCloud.net
marakana.commarakana.com
RSpec SubjectRSpec Subject
describe Address do
it “must have a street” do
a = Address.new
a.should_not be_valid
a.errors.on(:street).should_not be_nil
end
#subject { Address.new } # Can be omitted if .new
# on same class as in describe
it “must have a street” do
should_not be_valid # should is called on
# subject by default
subject.errors.on(:street).should_not be_nil
end
end
HomeworkHomework
People
Customer
Order
customer_id
Item
OrderItem
order_id
item_id
STI Inheritance
Single-Table InheritanceSingle-Table Inheritance
class Person < ActiveRecord::Base
end
class Customer < Person
end
Derived class inherits
associations,
named_scope's,
validation rules,
methods,
...
Mocks,Mocks,
Doubles,Doubles,
Stubs, ...Stubs, ...
Object levelObject level
All three create a “mock”
object.
mock(), stub(), double() at
the Object level are
synonymous
Name for error reporting
m = mock(“A Mock”)
m = stub(“A Mock”)
m = double(“A Mock”)
Using MocksUsing Mocks
Mocks can have method
stubs.
They can be called like
methods.
Method stubs can return
values.
Mocks can be set up with
built-in method stubs.
m = mock(“A Mock”)
m.stub(:foo)
m.foo => nil
m.stub(:foo).
and_return(“hello”)
m.foo => “hello”
m = mock(“A Mock”,
:foo => “hello”)
Message ExpectationsMessage Expectations
Mocks can carry message
expectations.
should_receive expects a
single call by default
Message expectations can
return values.
Can expect multiple calls.
m = mock(“A Mock”)
m.should_receive(:foo)
m.should_receive(:foo).
and_return(“hello”)
m.should_receive(:foo).
twice
m.should_receive(:foo).
exactly(5).times
Argument ExpectationsArgument Expectations
Regular expressions
Hash keys
Block
m = mock(“A Mock”)
m.should_receive(:foo).
with(/ello/)
with(hash_including(
:name => 'joe'))
with { |arg1, arg2|
arg1.should == 'abc'
arg2.should == 2
}
Partial MocksPartial Mocks
Replace a method on an
existing class.
Add a method to an
existing class.
jan1 =
Time.civil(2010)
Time.stub!(:now).
and_return(jan1)
Time.stub!(:jan1).
and_return(jan1)
Dangers
of
Mocks
ProblemsProblems
Non-DRY
Simulated API vs. actual API
Maintenance
Simulated API gets out of sync with actual API
Tedious to remove after “outside-in” phase
Leads to testing implementation, not effect
Demands on integration and exploratory testing
higher with mocks.
Less value per line of test code!
So what are they good for?So what are they good for?
External services
API's
System services
Time
I/O, Files, ...
Sufficiently mature (!) internal API's
Slow queries
Queries with complicated data setup
ControllersControllers
ControllersControllers
Controllers are pass-through entities
Mostly boilerplate—biz logic belongs in the model
Controllers are “dumb” or “skinny”
They follow a run-of-the mill pattern:
the Controller Formula
Controller RESTful ActionsController RESTful Actions
Display methods (“Read”)
GET: index, show, new, edit
Update method
PUT
Create method
POST
Delete method
DELETE
REST?REST?
Representational State Transfer
All resource-based applications & API's need to
do similar things, namely:
create, read, update, delete
It's a convention:
no configuration, no ceremony
superior to CORBA, SOAP, etc.
RESTful rsources in RailsRESTful rsources in Rails
map.resources :people (in config/routes.rb)
people_path, people_url “named route methods”
GET /people → “index” action
POST /people → “create” action
new_person_path, new_person_url
GET /people/new → “new” action
edit_person_path, edit_person_url
GET /people/:id/edit → “edit” action with ID
person_path, person_url
GET /people/:id → “show” action with ID
PUT /people/:id → “update” action with ID
DELETE /people/:id → “destroy” action with ID
Reads Test PatternReads Test Pattern
Make request (with id of record if a single record)
Check Rendering
correct template
redirect
status code
content type (HTML, JSON, XML,...)
Verify Variable Assignments
required by view
Read FormulaRead Formula
Find data, based on parameters
Assign variables
Render
How much test is too much?How much test is too much?
Test anything where the code deviates from
defaults, e.g. redirect vs. straight up render
These tests are not strictly necessary:
response.should be_success
response.should render_template('new')
Test anything required for the application to
proceed without error
Speficially variable assignments
Do test error handling code!
form_for's automagic powersform_for's automagic powers
form_for @person do |f| ... end
When @person is new
→ <form action=”people” method=”post”>
→ PeopleController#create
→ uses people_path method to generate URL
When @person exists already
→ <form action=”people” method=”put”>
→ PeopleController#update
→ uses person_path method to generate URL
Create/Update Test PatternCreate/Update Test Pattern
Make request with form fields to be created/upd'd
Verify Variable Assignments
Verify Check Success
Rendering
Verify Failure/Error Case
Rendering
Variables
Verify HTTP Verb protection
Create/Update FormulaCreate/Update Formula
Update: Find record from parameters
Create: Instantiate new model object
Assign form fields parameters to model object
This should be a single line
It is a pattern, the “Controller Formula”
Save
Handle success—typically a redirect
Handle failure—typically a render
Destroy Test PatternDestroy Test Pattern
Make request with id of record to be destroyed
Rendering
Typically no need to check for success or failure
Invalid item referenced → Same behavior as read
Database deletion failed → System not user error
Destroy FormulaDestroy Formula
Find record from parameters
Destroy
Redirect
How much is enough?How much is enough?
Notice: No view testing so far.
Emphasize behavior over display.
Check that the application handles errors
correctly
Test views only for things that could go wrong
badly
incorrect form URL
incorrect names on complicated forms, because they
impact parameter representation
View TestingView Testing
RSpec controllers do not render views (by
default)
Test form urls, any logic and input names
Understand CSS selector syntax
View test requires set up of variables
another reason why there should only be very few
variables between controller and view
A note on RJSA note on RJS
RJS lets you render a JS response using “RJS”
Built on Prototype JS framework
Hard to test
Largely superseded by
RSpec tested controllers responding in JSON
JS tests mocking the server response
jQuery's Ajax library very helpful
RSpec Scaffold & MocksRSpec Scaffold & Mocks
RSpec Scaffold mocks models
Their philosophy is outside-in development
I'm not a fan of this because:
It causes gaps in coverage
Mocks need to be maintained
Outside-in remains unproven beyond textbook
examples
When taken to the extreme, it can become un-Agile
by over-specifying the application
NestedNested
AttributesAttributes
One Form—Multiple ModelsOne Form—Multiple Models
DB schema should not limit view/form layout
View/form layout should not impose DB schema
A single form to manipulate associated rows of
multiple tables.
→ Nested Attributes
View & Model CollaborationView & Model Collaboration
Model:
accepts_nested_attributes_for
View:
form_for
fields_for
Controller is unaware! Strictly pass-through
Person.new(params[:person])
accepts_nested_attributes_foraccepts_nested_attributes_for
class Person < ActiveRecord::Base
has_many :addresses
accepts_nested_attributes_for :person
end
Person.create(:first_name => “Joe”,
:last_name => “Smith”,
:addresses_attributes => [ {
:street => “123 Main,
:city => “San Francisco”,
:zip => “94103”,
:state => “CA” } ]
HomeworkHomework
HomeworkHomework
As a person, I can enter or update my name
along with 2 addresses on the same form.
Extra credit:
As a customer, I can order multiple items from a
list of items.
On the order form, I can click “add one” to add an
item.
On the order form, I can click “remove” next to
each item already on the order.
Recommended ReadingRecommended Reading
Nested Attributes API Docs: http://bit.ly/7cnt0
Form for (with nest'd attr's) API Docs:
http://bit.ly/9DAscq
My presentation on nested attributes:
http://blip.tv/file/3957941
RSpec book chapter 14 (on Mocks)
RSpec book chapters 1.5, 10, 11 (on BDD)
RSpec book chapter 20 (outside-in development)
Flickr Photo Attribute CreditFlickr Photo Attribute Credit
Matroshka nested dolls
http://www.flickr.com/photos/shereen84/2511071028/sizes/l/
Notebook with pencil
http://www.flickr.com/photos/tomsaint/2987926396/sizes/l/
Danger Sign
http://www.flickr.com/photos/lwr/132854217/sizes/l/
Control Panel
http://www.flickr.com/photos/900hp/3961052527/sizes/l/
Mocking Clown
http://www.flickr.com/photos/bcostin/134531379/sizes/l/

More Related Content

What's hot

MVC & SQL_In_1_Hour
MVC & SQL_In_1_HourMVC & SQL_In_1_Hour
MVC & SQL_In_1_HourDilip Patel
 
Handlebars and Require.js
Handlebars and Require.jsHandlebars and Require.js
Handlebars and Require.jsIvano Malavolta
 
Testing Ext JS and Sencha Touch
Testing Ext JS and Sencha TouchTesting Ext JS and Sencha Touch
Testing Ext JS and Sencha TouchMats Bryntse
 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engineWO Community
 
Two scoops of django 1.6 - Ch7, Ch8
Two scoops of django 1.6  - Ch7, Ch8Two scoops of django 1.6  - Ch7, Ch8
Two scoops of django 1.6 - Ch7, Ch8flywindy
 
Angular or Backbone: Go Mobile!
Angular or Backbone: Go Mobile!Angular or Backbone: Go Mobile!
Angular or Backbone: Go Mobile!Doris Chen
 
Introduction to Sightly
Introduction to SightlyIntroduction to Sightly
Introduction to SightlyAnkit Gubrani
 
Jquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript BasicsJquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript BasicsEPAM Systems
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Fabien Potencier
 
Coding with style: The Scalastyle style checker
Coding with style: The Scalastyle style checkerCoding with style: The Scalastyle style checker
Coding with style: The Scalastyle style checkerMatthew Farwell
 
An Introduction to Ruby on Rails
An Introduction to Ruby on RailsAn Introduction to Ruby on Rails
An Introduction to Ruby on RailsJoe Fiorini
 
Jasig Rubyon Rails
Jasig Rubyon RailsJasig Rubyon Rails
Jasig Rubyon RailsPaul Pajo
 
Unit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsUnit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsYnon Perek
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful ControllersWO Community
 
25 Real Life Tips In Ruby on Rails Development
25 Real Life Tips In Ruby on Rails Development25 Real Life Tips In Ruby on Rails Development
25 Real Life Tips In Ruby on Rails DevelopmentBelighted
 

What's hot (20)

MVC & SQL_In_1_Hour
MVC & SQL_In_1_HourMVC & SQL_In_1_Hour
MVC & SQL_In_1_Hour
 
Handlebars and Require.js
Handlebars and Require.jsHandlebars and Require.js
Handlebars and Require.js
 
Selenium bootcamp slides
Selenium bootcamp slides   Selenium bootcamp slides
Selenium bootcamp slides
 
Testing Ext JS and Sencha Touch
Testing Ext JS and Sencha TouchTesting Ext JS and Sencha Touch
Testing Ext JS and Sencha Touch
 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
 
Two scoops of django 1.6 - Ch7, Ch8
Two scoops of django 1.6  - Ch7, Ch8Two scoops of django 1.6  - Ch7, Ch8
Two scoops of django 1.6 - Ch7, Ch8
 
Angular or Backbone: Go Mobile!
Angular or Backbone: Go Mobile!Angular or Backbone: Go Mobile!
Angular or Backbone: Go Mobile!
 
Introduction to Sightly
Introduction to SightlyIntroduction to Sightly
Introduction to Sightly
 
Wt unit 5 client &amp; server side framework
Wt unit 5 client &amp; server side frameworkWt unit 5 client &amp; server side framework
Wt unit 5 client &amp; server side framework
 
Jquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript BasicsJquery Complete Presentation along with Javascript Basics
Jquery Complete Presentation along with Javascript Basics
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
Coding with style: The Scalastyle style checker
Coding with style: The Scalastyle style checkerCoding with style: The Scalastyle style checker
Coding with style: The Scalastyle style checker
 
An Introduction to Ruby on Rails
An Introduction to Ruby on RailsAn Introduction to Ruby on Rails
An Introduction to Ruby on Rails
 
Jasig Rubyon Rails
Jasig Rubyon RailsJasig Rubyon Rails
Jasig Rubyon Rails
 
Flask restless
Flask restlessFlask restless
Flask restless
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
 
Unit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsUnit Testing JavaScript Applications
Unit Testing JavaScript Applications
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
 
25 Real Life Tips In Ruby on Rails Development
25 Real Life Tips In Ruby on Rails Development25 Real Life Tips In Ruby on Rails Development
25 Real Life Tips In Ruby on Rails Development
 

Viewers also liked

Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo
Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas EneboLearn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo
Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas EneboMarakana Inc.
 
JClouds at San Francisco Java User Group
JClouds at San Francisco Java User GroupJClouds at San Francisco Java User Group
JClouds at San Francisco Java User GroupMarakana Inc.
 
What's this jQuery? Where it came from, and how it will drive innovation
What's this jQuery? Where it came from, and how it will drive innovationWhat's this jQuery? Where it came from, and how it will drive innovation
What's this jQuery? Where it came from, and how it will drive innovationMarakana Inc.
 
Pictures from "Learn about RenderScript" meetup at SF Android User Group
Pictures from "Learn about RenderScript" meetup at SF Android User GroupPictures from "Learn about RenderScript" meetup at SF Android User Group
Pictures from "Learn about RenderScript" meetup at SF Android User GroupMarakana Inc.
 
2010 07-18.wa.rails tdd-6
2010 07-18.wa.rails tdd-62010 07-18.wa.rails tdd-6
2010 07-18.wa.rails tdd-6Marakana Inc.
 
The State of Nextwave Greentech Investing
The State of Nextwave Greentech InvestingThe State of Nextwave Greentech Investing
The State of Nextwave Greentech Investinggreentechmediaevents
 
The Latest on Semantic Web
The Latest on Semantic WebThe Latest on Semantic Web
The Latest on Semantic WebMarakana Inc.
 
Martin Odersky: What's next for Scala
Martin Odersky: What's next for ScalaMartin Odersky: What's next for Scala
Martin Odersky: What's next for ScalaMarakana Inc.
 
Why Java Needs Hierarchical Data
Why Java Needs Hierarchical DataWhy Java Needs Hierarchical Data
Why Java Needs Hierarchical DataMarakana Inc.
 
Latest on Semantic Web
Latest on Semantic WebLatest on Semantic Web
Latest on Semantic WebShamod Lacoul
 

Viewers also liked (10)

Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo
Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas EneboLearn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo
Learn about JRuby Internals from one of the JRuby Lead Developers, Thomas Enebo
 
JClouds at San Francisco Java User Group
JClouds at San Francisco Java User GroupJClouds at San Francisco Java User Group
JClouds at San Francisco Java User Group
 
What's this jQuery? Where it came from, and how it will drive innovation
What's this jQuery? Where it came from, and how it will drive innovationWhat's this jQuery? Where it came from, and how it will drive innovation
What's this jQuery? Where it came from, and how it will drive innovation
 
Pictures from "Learn about RenderScript" meetup at SF Android User Group
Pictures from "Learn about RenderScript" meetup at SF Android User GroupPictures from "Learn about RenderScript" meetup at SF Android User Group
Pictures from "Learn about RenderScript" meetup at SF Android User Group
 
2010 07-18.wa.rails tdd-6
2010 07-18.wa.rails tdd-62010 07-18.wa.rails tdd-6
2010 07-18.wa.rails tdd-6
 
The State of Nextwave Greentech Investing
The State of Nextwave Greentech InvestingThe State of Nextwave Greentech Investing
The State of Nextwave Greentech Investing
 
The Latest on Semantic Web
The Latest on Semantic WebThe Latest on Semantic Web
The Latest on Semantic Web
 
Martin Odersky: What's next for Scala
Martin Odersky: What's next for ScalaMartin Odersky: What's next for Scala
Martin Odersky: What's next for Scala
 
Why Java Needs Hierarchical Data
Why Java Needs Hierarchical DataWhy Java Needs Hierarchical Data
Why Java Needs Hierarchical Data
 
Latest on Semantic Web
Latest on Semantic WebLatest on Semantic Web
Latest on Semantic Web
 

Similar to Efficient Rails Test Driven Development (class 3) by Wolfram Arnold

2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD WorkshopWolfram Arnold
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Railsrstankov
 
Practical catalyst
Practical catalystPractical catalyst
Practical catalystdwm042
 
Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...Eelco Visser
 
Strategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific LanguagesStrategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific LanguagesEelco Visser
 
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Joao Lucas Santana
 
AEM Sightly Deep Dive
AEM Sightly Deep DiveAEM Sightly Deep Dive
AEM Sightly Deep DiveGabriel Walt
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le WagonAlex Benoit
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsMike Subelsky
 
2010-07-19_rails_tdd_week1
2010-07-19_rails_tdd_week12010-07-19_rails_tdd_week1
2010-07-19_rails_tdd_week1Wolfram Arnold
 
Working with LoopBack Models
Working with LoopBack ModelsWorking with LoopBack Models
Working with LoopBack ModelsRaymond Feng
 
Web performance essentials - Goodies
Web performance essentials - GoodiesWeb performance essentials - Goodies
Web performance essentials - GoodiesJerry Emmanuel
 
RoR 101: Session 2
RoR 101: Session 2RoR 101: Session 2
RoR 101: Session 2Rory Gianni
 
Ruby on Rails: Coding Guideline
Ruby on Rails: Coding GuidelineRuby on Rails: Coding Guideline
Ruby on Rails: Coding GuidelineNascenia IT
 
Intro to-html-backbone
Intro to-html-backboneIntro to-html-backbone
Intro to-html-backbonezonathen
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperfNew Relic
 

Similar to Efficient Rails Test Driven Development (class 3) by Wolfram Arnold (20)

2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
Practical catalyst
Practical catalystPractical catalyst
Practical catalyst
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...
 
Strategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific LanguagesStrategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific Languages
 
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
 
AEM Sightly Deep Dive
AEM Sightly Deep DiveAEM Sightly Deep Dive
AEM Sightly Deep Dive
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le Wagon
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Supa fast Ruby + Rails
Supa fast Ruby + RailsSupa fast Ruby + Rails
Supa fast Ruby + Rails
 
2010-07-19_rails_tdd_week1
2010-07-19_rails_tdd_week12010-07-19_rails_tdd_week1
2010-07-19_rails_tdd_week1
 
Working with LoopBack Models
Working with LoopBack ModelsWorking with LoopBack Models
Working with LoopBack Models
 
Web performance essentials - Goodies
Web performance essentials - GoodiesWeb performance essentials - Goodies
Web performance essentials - Goodies
 
RoR 101: Session 2
RoR 101: Session 2RoR 101: Session 2
RoR 101: Session 2
 
Ruby on Rails: Coding Guideline
Ruby on Rails: Coding GuidelineRuby on Rails: Coding Guideline
Ruby on Rails: Coding Guideline
 
Intro to-html-backbone
Intro to-html-backboneIntro to-html-backbone
Intro to-html-backbone
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 

More from Marakana Inc.

Android Services Black Magic by Aleksandar Gargenta
Android Services Black Magic by Aleksandar GargentaAndroid Services Black Magic by Aleksandar Gargenta
Android Services Black Magic by Aleksandar GargentaMarakana Inc.
 
Behavior Driven Development
Behavior Driven DevelopmentBehavior Driven Development
Behavior Driven DevelopmentMarakana Inc.
 
Deep Dive Into Android Security
Deep Dive Into Android SecurityDeep Dive Into Android Security
Deep Dive Into Android SecurityMarakana Inc.
 
Android UI Tips, Tricks and Techniques
Android UI Tips, Tricks and TechniquesAndroid UI Tips, Tricks and Techniques
Android UI Tips, Tricks and TechniquesMarakana Inc.
 
Graphicsand animations devoxx2010 (1)
Graphicsand animations devoxx2010 (1)Graphicsand animations devoxx2010 (1)
Graphicsand animations devoxx2010 (1)Marakana Inc.
 
jQuery State of the Union - Yehuda Katz
jQuery State of the Union - Yehuda KatzjQuery State of the Union - Yehuda Katz
jQuery State of the Union - Yehuda KatzMarakana Inc.
 
Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...
Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...
Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...Marakana Inc.
 
Replacing Java Incrementally
Replacing Java IncrementallyReplacing Java Incrementally
Replacing Java IncrementallyMarakana Inc.
 
Learn to Build like you Code with Apache Buildr
Learn to Build like you Code with Apache BuildrLearn to Build like you Code with Apache Buildr
Learn to Build like you Code with Apache BuildrMarakana Inc.
 
Learn How to Unit Test Your Android Application (with Robolectric)
Learn How to Unit Test Your Android Application (with Robolectric)Learn How to Unit Test Your Android Application (with Robolectric)
Learn How to Unit Test Your Android Application (with Robolectric)Marakana Inc.
 
Learn Learn how to build your mobile back-end with MongoDB
Learn Learn how to build your mobile back-end with MongoDBLearn Learn how to build your mobile back-end with MongoDB
Learn Learn how to build your mobile back-end with MongoDBMarakana Inc.
 
A hands on overview of the semantic web
A hands on overview of the semantic webA hands on overview of the semantic web
A hands on overview of the semantic webMarakana Inc.
 
Super simple application security with Apache Shiro
Super simple application security with Apache ShiroSuper simple application security with Apache Shiro
Super simple application security with Apache ShiroMarakana Inc.
 
Overview of Java EE 6 by Roberto Chinnici at SFJUG
Overview of Java EE 6 by Roberto Chinnici at SFJUGOverview of Java EE 6 by Roberto Chinnici at SFJUG
Overview of Java EE 6 by Roberto Chinnici at SFJUGMarakana Inc.
 
JavaEE 6 and GlassFish v3 at SFJUG
JavaEE 6 and GlassFish v3 at SFJUGJavaEE 6 and GlassFish v3 at SFJUG
JavaEE 6 and GlassFish v3 at SFJUGMarakana Inc.
 
Android casting-wide-net-android-devices
Android casting-wide-net-android-devicesAndroid casting-wide-net-android-devices
Android casting-wide-net-android-devicesMarakana Inc.
 
JClouds at San Francisco Java User Group
JClouds at San Francisco Java User GroupJClouds at San Francisco Java User Group
JClouds at San Francisco Java User GroupMarakana Inc.
 

More from Marakana Inc. (20)

Android Services Black Magic by Aleksandar Gargenta
Android Services Black Magic by Aleksandar GargentaAndroid Services Black Magic by Aleksandar Gargenta
Android Services Black Magic by Aleksandar Gargenta
 
JRuby at Square
JRuby at SquareJRuby at Square
JRuby at Square
 
Behavior Driven Development
Behavior Driven DevelopmentBehavior Driven Development
Behavior Driven Development
 
Deep Dive Into Android Security
Deep Dive Into Android SecurityDeep Dive Into Android Security
Deep Dive Into Android Security
 
Securing Android
Securing AndroidSecuring Android
Securing Android
 
Android UI Tips, Tricks and Techniques
Android UI Tips, Tricks and TechniquesAndroid UI Tips, Tricks and Techniques
Android UI Tips, Tricks and Techniques
 
Graphicsand animations devoxx2010 (1)
Graphicsand animations devoxx2010 (1)Graphicsand animations devoxx2010 (1)
Graphicsand animations devoxx2010 (1)
 
jQuery State of the Union - Yehuda Katz
jQuery State of the Union - Yehuda KatzjQuery State of the Union - Yehuda Katz
jQuery State of the Union - Yehuda Katz
 
Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...
Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...
Pics from: "James Gosling on Apple, Apache, Google, Oracle and the Future of ...
 
Replacing Java Incrementally
Replacing Java IncrementallyReplacing Java Incrementally
Replacing Java Incrementally
 
Learn to Build like you Code with Apache Buildr
Learn to Build like you Code with Apache BuildrLearn to Build like you Code with Apache Buildr
Learn to Build like you Code with Apache Buildr
 
Learn How to Unit Test Your Android Application (with Robolectric)
Learn How to Unit Test Your Android Application (with Robolectric)Learn How to Unit Test Your Android Application (with Robolectric)
Learn How to Unit Test Your Android Application (with Robolectric)
 
Learn Learn how to build your mobile back-end with MongoDB
Learn Learn how to build your mobile back-end with MongoDBLearn Learn how to build your mobile back-end with MongoDB
Learn Learn how to build your mobile back-end with MongoDB
 
A hands on overview of the semantic web
A hands on overview of the semantic webA hands on overview of the semantic web
A hands on overview of the semantic web
 
Jena framework
Jena frameworkJena framework
Jena framework
 
Super simple application security with Apache Shiro
Super simple application security with Apache ShiroSuper simple application security with Apache Shiro
Super simple application security with Apache Shiro
 
Overview of Java EE 6 by Roberto Chinnici at SFJUG
Overview of Java EE 6 by Roberto Chinnici at SFJUGOverview of Java EE 6 by Roberto Chinnici at SFJUG
Overview of Java EE 6 by Roberto Chinnici at SFJUG
 
JavaEE 6 and GlassFish v3 at SFJUG
JavaEE 6 and GlassFish v3 at SFJUGJavaEE 6 and GlassFish v3 at SFJUG
JavaEE 6 and GlassFish v3 at SFJUG
 
Android casting-wide-net-android-devices
Android casting-wide-net-android-devicesAndroid casting-wide-net-android-devices
Android casting-wide-net-android-devices
 
JClouds at San Francisco Java User Group
JClouds at San Francisco Java User GroupJClouds at San Francisco Java User Group
JClouds at San Francisco Java User Group
 

Recently uploaded

Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetHyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetEnjoy Anytime
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 

Recently uploaded (20)

Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetHyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 

Efficient Rails Test Driven Development (class 3) by Wolfram Arnold

  • 1. Efficient Rails Test-DrivenEfficient Rails Test-Driven Development — Week 3Development — Week 3 Wolfram ArnoldWolfram Arnold www.rubyfocus.bizwww.rubyfocus.biz In collaboration with:In collaboration with: Sarah Allen, BlazingCloud.netSarah Allen, BlazingCloud.net marakana.commarakana.com
  • 2. RSpec SubjectRSpec Subject describe Address do it “must have a street” do a = Address.new a.should_not be_valid a.errors.on(:street).should_not be_nil end #subject { Address.new } # Can be omitted if .new # on same class as in describe it “must have a street” do should_not be_valid # should is called on # subject by default subject.errors.on(:street).should_not be_nil end end
  • 4. Single-Table InheritanceSingle-Table Inheritance class Person < ActiveRecord::Base end class Customer < Person end Derived class inherits associations, named_scope's, validation rules, methods, ...
  • 6. Object levelObject level All three create a “mock” object. mock(), stub(), double() at the Object level are synonymous Name for error reporting m = mock(“A Mock”) m = stub(“A Mock”) m = double(“A Mock”)
  • 7. Using MocksUsing Mocks Mocks can have method stubs. They can be called like methods. Method stubs can return values. Mocks can be set up with built-in method stubs. m = mock(“A Mock”) m.stub(:foo) m.foo => nil m.stub(:foo). and_return(“hello”) m.foo => “hello” m = mock(“A Mock”, :foo => “hello”)
  • 8. Message ExpectationsMessage Expectations Mocks can carry message expectations. should_receive expects a single call by default Message expectations can return values. Can expect multiple calls. m = mock(“A Mock”) m.should_receive(:foo) m.should_receive(:foo). and_return(“hello”) m.should_receive(:foo). twice m.should_receive(:foo). exactly(5).times
  • 9. Argument ExpectationsArgument Expectations Regular expressions Hash keys Block m = mock(“A Mock”) m.should_receive(:foo). with(/ello/) with(hash_including( :name => 'joe')) with { |arg1, arg2| arg1.should == 'abc' arg2.should == 2 }
  • 10. Partial MocksPartial Mocks Replace a method on an existing class. Add a method to an existing class. jan1 = Time.civil(2010) Time.stub!(:now). and_return(jan1) Time.stub!(:jan1). and_return(jan1)
  • 12. ProblemsProblems Non-DRY Simulated API vs. actual API Maintenance Simulated API gets out of sync with actual API Tedious to remove after “outside-in” phase Leads to testing implementation, not effect Demands on integration and exploratory testing higher with mocks. Less value per line of test code!
  • 13. So what are they good for?So what are they good for? External services API's System services Time I/O, Files, ... Sufficiently mature (!) internal API's Slow queries Queries with complicated data setup
  • 15. ControllersControllers Controllers are pass-through entities Mostly boilerplate—biz logic belongs in the model Controllers are “dumb” or “skinny” They follow a run-of-the mill pattern: the Controller Formula
  • 16. Controller RESTful ActionsController RESTful Actions Display methods (“Read”) GET: index, show, new, edit Update method PUT Create method POST Delete method DELETE
  • 17. REST?REST? Representational State Transfer All resource-based applications & API's need to do similar things, namely: create, read, update, delete It's a convention: no configuration, no ceremony superior to CORBA, SOAP, etc.
  • 18. RESTful rsources in RailsRESTful rsources in Rails map.resources :people (in config/routes.rb) people_path, people_url “named route methods” GET /people → “index” action POST /people → “create” action new_person_path, new_person_url GET /people/new → “new” action edit_person_path, edit_person_url GET /people/:id/edit → “edit” action with ID person_path, person_url GET /people/:id → “show” action with ID PUT /people/:id → “update” action with ID DELETE /people/:id → “destroy” action with ID
  • 19. Reads Test PatternReads Test Pattern Make request (with id of record if a single record) Check Rendering correct template redirect status code content type (HTML, JSON, XML,...) Verify Variable Assignments required by view
  • 20. Read FormulaRead Formula Find data, based on parameters Assign variables Render
  • 21. How much test is too much?How much test is too much? Test anything where the code deviates from defaults, e.g. redirect vs. straight up render These tests are not strictly necessary: response.should be_success response.should render_template('new') Test anything required for the application to proceed without error Speficially variable assignments Do test error handling code!
  • 22. form_for's automagic powersform_for's automagic powers form_for @person do |f| ... end When @person is new → <form action=”people” method=”post”> → PeopleController#create → uses people_path method to generate URL When @person exists already → <form action=”people” method=”put”> → PeopleController#update → uses person_path method to generate URL
  • 23. Create/Update Test PatternCreate/Update Test Pattern Make request with form fields to be created/upd'd Verify Variable Assignments Verify Check Success Rendering Verify Failure/Error Case Rendering Variables Verify HTTP Verb protection
  • 24. Create/Update FormulaCreate/Update Formula Update: Find record from parameters Create: Instantiate new model object Assign form fields parameters to model object This should be a single line It is a pattern, the “Controller Formula” Save Handle success—typically a redirect Handle failure—typically a render
  • 25. Destroy Test PatternDestroy Test Pattern Make request with id of record to be destroyed Rendering Typically no need to check for success or failure Invalid item referenced → Same behavior as read Database deletion failed → System not user error
  • 26. Destroy FormulaDestroy Formula Find record from parameters Destroy Redirect
  • 27. How much is enough?How much is enough? Notice: No view testing so far. Emphasize behavior over display. Check that the application handles errors correctly Test views only for things that could go wrong badly incorrect form URL incorrect names on complicated forms, because they impact parameter representation
  • 28. View TestingView Testing RSpec controllers do not render views (by default) Test form urls, any logic and input names Understand CSS selector syntax View test requires set up of variables another reason why there should only be very few variables between controller and view
  • 29. A note on RJSA note on RJS RJS lets you render a JS response using “RJS” Built on Prototype JS framework Hard to test Largely superseded by RSpec tested controllers responding in JSON JS tests mocking the server response jQuery's Ajax library very helpful
  • 30. RSpec Scaffold & MocksRSpec Scaffold & Mocks RSpec Scaffold mocks models Their philosophy is outside-in development I'm not a fan of this because: It causes gaps in coverage Mocks need to be maintained Outside-in remains unproven beyond textbook examples When taken to the extreme, it can become un-Agile by over-specifying the application
  • 32. One Form—Multiple ModelsOne Form—Multiple Models DB schema should not limit view/form layout View/form layout should not impose DB schema A single form to manipulate associated rows of multiple tables. → Nested Attributes
  • 33. View & Model CollaborationView & Model Collaboration Model: accepts_nested_attributes_for View: form_for fields_for Controller is unaware! Strictly pass-through Person.new(params[:person])
  • 34. accepts_nested_attributes_foraccepts_nested_attributes_for class Person < ActiveRecord::Base has_many :addresses accepts_nested_attributes_for :person end Person.create(:first_name => “Joe”, :last_name => “Smith”, :addresses_attributes => [ { :street => “123 Main, :city => “San Francisco”, :zip => “94103”, :state => “CA” } ]
  • 36. HomeworkHomework As a person, I can enter or update my name along with 2 addresses on the same form. Extra credit: As a customer, I can order multiple items from a list of items. On the order form, I can click “add one” to add an item. On the order form, I can click “remove” next to each item already on the order.
  • 37. Recommended ReadingRecommended Reading Nested Attributes API Docs: http://bit.ly/7cnt0 Form for (with nest'd attr's) API Docs: http://bit.ly/9DAscq My presentation on nested attributes: http://blip.tv/file/3957941 RSpec book chapter 14 (on Mocks) RSpec book chapters 1.5, 10, 11 (on BDD) RSpec book chapter 20 (outside-in development)
  • 38. Flickr Photo Attribute CreditFlickr Photo Attribute Credit Matroshka nested dolls http://www.flickr.com/photos/shereen84/2511071028/sizes/l/ Notebook with pencil http://www.flickr.com/photos/tomsaint/2987926396/sizes/l/ Danger Sign http://www.flickr.com/photos/lwr/132854217/sizes/l/ Control Panel http://www.flickr.com/photos/900hp/3961052527/sizes/l/ Mocking Clown http://www.flickr.com/photos/bcostin/134531379/sizes/l/