ppt - CS Course Webpages

Explicit vs. Implicit
and Imperative vs.
Declarative
Scenarios
(Engineering Software
as a Service §7.9)
© 2013 Armando Fox & David Patterson, all rights reserved
1
Types of Scenarios
• Are all requirements directly from the User
Stories?
• Scenarios should have 3 to 8 steps; is there
a way to keep them closer to 3 than to 8?
2
Explicit vs. Implicit Scenarios
• Explicit requirements usually part of
acceptance tests
– Likely explicit user stories and scenarios:
list movies
• Implicit requirements are logical
consequence of explicit requirements,
typically integration testing
– Movies listed in chronological order or
alphabetical order?
3
Imperative vs. Declarative
Scenarios
• Imperative: Initial user stories with many
steps, specifying logical sequence to
desired result
– Not-DRY if many user stories imperative
• Declarative: describe state, not sequence
– Fewer steps
• Example Feature: movies should appear in
alphabetical order, not added order
• Example Scenario: view movie list after
adding 2 movies
4
Example Imperative Scenario
Given I am on the
Create New Movie page
RottenPotatoes home page
When I fill in "Title" with
When I follow "Add new
"Apocalypse Now"
movie"
And I select "R" from
Then I should be on the
"Rating"
Create New Movie page
And I press "Save Changes"
When I fill in "Title" with Then I should be on the
"Zorro"
RottenPotatoes home page
And I select "PG" from
When I follow ”Movie Title"
"Rating"
Then I should see
And I press "Save Changes"
"Apocalypse Now" before
Then I should be on the
"Zorro"
RottenPotatoes home page
Only step specifying behavior;
When I follow "Add new
Rest are implementation. But
movie"
BDD specifies behavior,
5
not implementation!
Then I should be on the
Domain Language
•
•
•
•
Declarative as if making domain language
Uses terms and concept of app
Informal language
Declarative steps describe the state app
should be in
– Imperative: sequence of steps to change
current state into desired state
6
Example Declarative Scenario
Feature: movies when added
should appear in movie
list
Scenario: view movie list
after adding movie
(declarative and DRY)
Given I have added
"Zorro" with rating "PG13"
And
I have added
"Apocalypse Now" with
rating "R"
Then I should see
"Apocalypse Now" before
"Zorro" on the Rotten
Potatoes home page
3 steps vs. 15 steps:
2 to set up test,
1 for behavior
Declarative scenarios focus
attention on feature being
described and tested vs.
steps needed to set up test
What about new step
definitions?
7
Declarative Scenario Needs
New Step Definitions
Given /I have added "(.*)" Then /I should see "(.*)"
with rating "(.*)"/ do
before "(.*)" on (.*)/ do
|title, rating|
|string1, string2, path|
steps %Q{Given I am on
step “I am on #{path}"
the Create New Movie page regexp =
When I fill in "Title"
/#{string1}.*#{string2}/m
with "#{title}”
# /m means match across
newlines
And I select "#{rating}"
from "Rating"
page.body.should =~
regexp
And I press "Save
Changes“}
end
end
• As app evolves, reuse steps from first few imperative scenarios
to create more concise and descriptive declarative scenarios
8
9
Which is TRUE about implicit vs. explicit
and declarative vs. imperative scenarios?
1. Explicit requirements are usually defined with
imperative scenarios and implicit requirements
are usually defined with declarative scenarios
2.
3. Declarative scenarios aim to capture
implementation as well as behavior
4. All are false
10
11
Fallacies & Pitfalls,
BDD Pros & Cons,
End of Chapter 7
(Engineering Software as
a Service §7.11)
© 2013 Armando Fox & David Patterson, all rights reserved
12
Pitfalls
• Customers confuse digital mock-ups with
completed features
– Nontechnical customers think highly polished
digital mock-up = working feature
• Use Lo-Fi mockups, as clearly
representations of proposed feature
13
Pitfalls
• Sketches without storyboards
– Need to reach agreement with customer on
interaction with pages as well as page content
• Storyboards / “animating” sketches reduces
misunderstandings
14
Pitfalls
• Adding cool features that do not make the
product more successful
– Customers reject what programmers liked
• Trying to predict what code you need before
need it
– BDD: write tests before you write code you
need, then write code needed to pass the tests
• User stories help prioritize & BDD minimizes
what you code => reduce wasted effort
15
Pitfalls
• Delivering a story as “done” when only the
happy path is tested
– Need to test both happy path and sad path
• Correct app behavior when user accidentally
does wrong thing is just as important as
correct behavior when does right thing
– To err is human
16
Pitfalls
• Careless use of negative expectations
– Beware of overusing “Then I should not see….”
– Can’t tell if output is what want, only that it is not
what you want
– Many, many outputs are incorrect
• Include positives to check results
“Then I should see …”
17
Pitfalls
• Careless use of positive expectations
– Then I should see “Emma”
what if string appears multiple times on page?
– Can pass even if feature not working
• Use Capybara’s within helper
– Constrains scope of matchers in a CSS selector
– Then I should see “Emma” within
“div#shopping_cart”
– See Capybara documentation
18
19
Which statement is FALSE about Lo-FI UI
and BDD?
1. The purpose of the Lo-Fi UI approach is to
debug the UI before you program it
2.
3. A BDD downside is that it may lead to a poor
software architecture, since focus is on behavior
4. None are false; all three above are true
20
21
How Popular is Agile?
• IT SW companies using Agile: Amazon, eBay,
Facebook, Microsoft, Salesforce, …
• 2011 Survey of UCB ESaaS Alumni in industry
– 68% Agile vs. 32% P&D (5% Spiral, 5% Waterfall)
• 2012 survey of 66 distributed projects*
– 55% Agile vs. 45% P&D
• Forrester: 60% teams use Agile as primary SW
development in 2012 vs. 45% in 2009**
• Gartner: 80% teams primarily Agile by end of 2012***
*H.-C. Estler, M. Nordio, C. A. Furia, B. Meyer, and J. Schneider. Agile vs. structured distributed software development: A
case study. Proc. 7th Int’l Conf. on Global Software Engineering (ICGSE’12), pp 11–20, 2012.
**http://articles.economictimes.indiatimes.com/2012-08-06/news/33065621_1_thoughtworks-software-development-iterative.
***http://www.pmi.org/en/Professional-Development/Career-Central/Must_Have_Skill_Agile.aspx.
22
Testing Tools in Book
Autotest
(Ch. 6)
Cucumber
(Ch. 5)
SimpleCov
(Ch. 6)
RSpec
(Ch. 6)
reek
(Ch. 8)
Capybara
(Ch. 5)
flog/flay
(Ch. 8)
Rack::Test
(Ch. 5)
Webdriver
(Ch. 12)
SauceLabs
(Ch. 12)
No JavaScript
JavaScript
JavaScript
+ Multiple Browsers
(Figure 7.15, Software as a
Service by Armando Fox and
David Patterson,
1st edition, 2013.)
23
BDD
Good & Bad
• User stories - common
language for all
stakeholders, including
nontechnical
– 3x5 cards
– LoFi UI sketches and
storyboards
• Write tests before
coding
• Difficult to have
continuous contact with
customer?
• Leads to bad software
architecture?
– Will cover design
patterns, refactoring in
future
– Validation by testing vs.
debugging
Images used for satire purposes only
24
BDD
• Doesn’t feel natural at first
• Rails tools make it easier to follow BDD
• Once learned BDD and had success at it, no
turning back
– 2/3 Alumni said BDD/TDD useful in industry
25
26
RSpec on Rails
(Engineering Software as a Service §8.2)
© 2012 Armando Fox & David Patterson
Licensed under Creative Commons AttributionNonCommercial-ShareAlike 3.0 Unported License
Rspec: Domain-Specific Language
for Testing
• RSpec tests (specs) inhabit spec directory
rails generate rspec:install creates
structure
• Unit tests (model, helpers)
• Functional tests (controllers)
• Integration tests (views)?
app/models/*.rb
app/controllers/
*_controller.rb
spec/models/*_spec.rb
spec/controllers/
*_controller_spec.rb
app/views/*/*.html.haml (use Cucumber!)
Example: Calling TMDb
• New RottenPotatoes feature: add movie using
info from TMDb (vs. typing in)
• How should user story steps behave?
When I fill in "Search Terms" with "Inception"
And I press "Search TMDb"
Then I should be on the RottenPotatoes homepage
...
Recall Rails Cookery #2:
adding new feature ==
new route+new controller method+new view
The Code You Wish You Had
What should the controller method do that
receives the search form?
1. It should call a method that will search
TMDb for specified movie
2. If match found: it should select (new)
“Search Results” view to display match
3. If no match found: it should redirect to RP
home page with message
http://pastebin.com/kJxjwSF6
31
The method that contacts TMDb to
search for a movie should be:
☐A class method of the Movie model
☐
☐ A controller method
☐ A helper method
32
33
The TDD Cycle:
Red–Green–Refactor
(Engineering Software as a Service §8.2)
© 2013 Armando Fox & David Patterson, all rights reserved
Test-First Development
• Think about one thing the code should do
• Capture that thought in a test, which fails
• Write the simplest possible code that lets the
test pass
• Refactor: DRY out commonality w/other tests
• Continue with next thing code should do
Red – Green – Refactor
Aim for “always have working code”
How to test something “in
isolation” if it has dependencies
that would affect test?
The Code You Wish You Had
What should the controller method do that
receives the search form?
1. It should call a method that will search
TMDb for specified movie
2. If match found: it should select (new)
“Search Results” view to display match
3. If no match found: it should redirect to RP
home page with message
TDD for the Controller Action: Setup
• Add a route to config/routes.rb
# Route that posts 'Search TMDb' form
post '/movies/search_tmdb'
– Convention over configuration will map this to
MoviesController#search_tmdb
• Create an empty view:
touch app/views/movies/search_tmdb.html.haml
• Replace fake “hardwired” sad path method in
movies_controller.rb with empty method:
def search_tmdb
end
What Model Method?
• Calling TMDb is responsibility of the model... but
no model method exists to do this yet!
• No problem...we’ll use a seam to test the code we
wish we had (“CWWWH”), Movie.find_in_tmdb
• Game plan:
– Simulate POSTing search form to controller action.
– Check that controller action tries to call
Movie.find_in_tmdb with data from submitted form
– The test will fail (red), because the (empty) controller
method doesn’t call find_in_tmdb
– Fix controller action to make green
http://pastebin.com/zKnwphQZ
40
Which is FALSE about should_receive?
It provides a stand-in for a real method
☐
that doesn’t exist yet
☐
☐ It can be issued either before or after the
code that should make the call
☐ It exploits Ruby’s open classes and
metaprogramming to create a seam
41
42
Seams
(Engineering Software as a Service §8.3)
© 2013 Armando Fox & David Patterson, all rights reserved
Seams
• A place where you can change app’s behavior
without changing source code.
(Michael Feathers, Working Effectively With Legacy Code)
• Useful for testing: isolate behavior of some code
from that of other code it depends on.
• should_receive uses Ruby’s open classes to
create a seam for isolating controller action from
behavior of (possibly buggy or missing)
Movie.find_in_tmdb
• Rspec resets all mocks & stubs after each
example (keep tests Independent)
How to Make This Spec Green?
• Expectation says controller action should
call Movie.find_in_tmdb
• So, let’s call it!
http://pastebin.com/DxzFURiu
The spec has driven the creation of the
controller method to pass the test
• But shouldn’t find_in_tmdb return
something?
Test Techniques We Know
obj.should_receive(a).with(b)
Optional!
47
Eventually we will have to write a real
find_in_tmdb. When that happens, we
should:
☐ Replace the call to should_receive in our
test with a call to the real find_in_tmdb
☐
find_in_tmdb
should_receive
Keep the should_receive seam in the spec,
☐
but if necessary, change the spec to match
the API of the real find_in_tmdb
☐ Remove this spec (test case) altogether since
it isn’t really testing anything anymore
48
49
Expectations
(Engineering Software as a Service §8.4)
© 2013 Armando Fox & David Patterson, all rights reserved
Where We Are & Where We’re Going:
“Outside In” Development
• Focus: write expectations that drive
development of controller method
– Discovered: must collaborate w/model method
– Use outside-in recursively: stub model method
in this test, write it later
• Key idea: break dependency between
method under test & its collaborators
• Key concept: seam—where you can
affect app behavior without editing code
The Code You Wish You Had
What should the controller method do that
receives the search form?
1. It should call a method that will search
TMDb for specified movie
2. If match found: it should select (new)
“Search Results” view to display match
3. If no match found: it should redirect to RP
home page with message
“It Should Select Search Results
View to Display Match”
• Really 2 specs:
1. It should decide to render Search Results
– more important when different views could be
rendered depending on outcome
2. It should make list of matches available to
that view
• New expectation construct:
obj.should match-condition
– Many built-in matchers, or define your own
Should & Should-Not
• Matcher applies test to receiver of should
count.should == 5`
Syntactic sugar for
count.should.==(5)
5.should(be.<(7))
be creates a lambda that tests
the predicate expression
5.should be < 7
5.should be_odd
Syntactic sugar allowed
result.should include(elt)
calls #include?, which usually
gets handled by Enumerable
republican.should
cooperate_with(democrat)
calls programmer’s custom
matcher #cooperate_with (and
probably fails)
Use method_missing to call
odd? on 5
result.should render_template('search_tmdb')
Checking for Rendering
• After post :search_tmdb, response()
method returns controller’s response object
• render_template matcher can check what
view the controller tried to render
http://pastebin.com/C2x13z8M
• Note that this view has to exist!
– post :search_tmdb will try to do the whole
MVC flow, including rendering the view
– hence, controller specs can be viewed as
functional testing
Test Techniques We Know
obj.should_receive(a).with(b)
obj.should match-condition
Rails-specific extensions to RSpec:
response()
render_template()
57
Which of these, if any, is not a valid
use of should or should_not?
☐ result.should_not be_empty
☐
☐ result.should_not match /^D'oh!$/
☐
All of the above are valid uses
58
59