• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
DevTeach12-betterspecs
 

DevTeach12-betterspecs

on

  • 750 views

Presentation done at Devteach/RubyTeach 2012

Presentation done at Devteach/RubyTeach 2012

Statistics

Views

Total Views
750
Views on SlideShare
750
Embed Views
0

Actions

Likes
1
Downloads
11
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    DevTeach12-betterspecs DevTeach12-betterspecs Presentation Transcript

    • Writing BetterDomain Oriented Cucumber Features Amir Barylko
    • Better Cucumber FeaturesWho am I?• Architect• Developer• Mentor• Great cook• The one who’s entertaining you for the next hour!
    • Behavior Driven Dev. Text Text The rSpec Book
    • Amir Barylko - Better Cucumber FeaturesWhy Projects Fail?• Delivering late or over budget• Delivering the wrong thing• Unstable in production• Costly to maintain
    • Amir Barylko - Better Cucumber FeaturesImprove Quality• Unit Testing• Integration Testing• Acceptance Testing
    • Amir Barylko - Better Cucumber FeaturesBDD• Implementing an application• by describing its behavior• from the perspective of the stakeholder
    • Amir Barylko - Better Cucumber FeaturesOutside In Approach BDD TDD
    • Amir Barylko - Better Cucumber FeaturesTest First• Write a test before any line of code• Write minimum amount of code to make the test pass• Refactor code to eliminate “smells”
    • Cucumber
    • Amir Barylko - Better Cucumber FeaturesGherkin DSL• Business readable DSL• Flush out requirements• Documentation• Automated testing• Used by Cucumber, SpecFlow, jBehave
    • Amir Barylko - Better Cucumber FeaturesGherkin Keywords• Feature • Then• Scenario • And• Given • But• When
    • Amir Barylko - Better Cucumber FeaturesFeaturesFeature: Listing projects As a user Free text! I Want to see the list of projects So I can choose one to see the details Scenario: List all projects (steps here to implement scenario) Scenario: No projects are available (steps here to implement scenario)
    • Amir Barylko - Better Cucumber FeaturesScenarioScenario: List all projects Given Im logged in Step 1 And I have some projects stored Step 2 When I browse the projects Step 3 Then I should see all of them listed Step 4
    • Amir Barylko - Better Cucumber FeaturesRunning Features• Parse the feature • Parse the scenario • For each scenario • Find a step implementation • Execute the code
    • Amir Barylko - Better Cucumber FeaturesMatching Step• Matching regular expression Given I have some projects stored Feature File Given /^I have some projects stored$/ Step Def File
    • Amir Barylko - Better Cucumber FeaturesStepGiven /^I have some projects stored$/ do projects = 10.times { random_valid_project } fake_response = create_response(projects) FakeWeb.register_uri(....)end Plain Ruby!
    • Expressive Scenarios
    • Amir Barylko - Better Cucumber FeaturesWhat we want?• Readability• Ubiquitous Language• Consistent use of terminology• Express natural business intent• Avoid technical aspects
    • Amir Barylko - Better Cucumber FeaturesImperative styleScenario: Redirect user to originally requested page Given a User "dave" exists with password "secret" And I am not logged in When I navigate to the home page Then I am redirected to the login form When I fill in "Username" with "dave" And I fill in "Password" with "secret" And I press "Login"
    • Amir Barylko - Better Cucumber FeaturesWhat’s the problem?• Who needs the passwords?• Tightly coupled to page implementation• Lacks domain language• Brittle tests• Does not tell a story (boring)
    • Amir Barylko - Better Cucumber FeaturesDeclarative styleScenario: Redirect user to originally requested page Given I am an authenticated user When I attempt to view restricted content Then I am presented with a login form When I authenticated with valid credentials Then I should be shown the restricted content
    • Amir Barylko - Better Cucumber FeaturesDeclarative vs Imperative• Imperative is associated to “how” to do it• Declarative is associated to “what” we want• Where’s the boundary?
    • Amir Barylko - Better Cucumber FeaturesToo abstract?Scenario: The whole system Given the system exists When I use it Then it should work, perfectly
    • Amir Barylko - Better Cucumber FeaturesBackground steps• Steps may have some degree of repetition• Because they start with the same “state”• So they share the first X steps
    • Amir Barylko - Better Cucumber FeaturesSimilar scenariosScenario: Change Password Given I am logged in And I choose to change my password When I enter a new password Then my password should be changedScenario: Change Password with same credentials Given I am logged in And I choose to change my password When I enter the same password Then I should see an error message explaining the problem
    • Amir Barylko - Better Cucumber FeaturesCreate BackgroundBackground: I want to change my password Given I am logged in And I choose to change my passwordScenario: Change Password When I enter a new password Then my password should be changedScenario: Change Password with same credentials When I enter the same password Then I should see an error message explaining the problem
    • Amir Barylko - Better Cucumber FeaturesUsing Tables• Sometimes data is hard to put in a step• with multiple entriesScenario: Listing movies Given the movie “Blazing saddles” released “7 Feb 1974” And the movie “Young Frankenstein” released “15 Dec 1974” And the movie “The Producers” released “10 Nov 1968”
    • Amir Barylko - Better Cucumber FeaturesThat’s boring!• Express data in tabular formScenario: Listing movies Given these movies: | title | release | | Blazing saddles | 7 Feb 1974 | | Young Frankenstein | 15 Dec 1974 | | The Producers | 10 Nov 1968 |
    • Amir Barylko - Better Cucumber FeaturesOr just a list• Don’t use the headerScenario: Listing movies Given these movies: | Blazing saddles | | Young Frankenstein | | The Producers |
    • Amir Barylko - Better Cucumber FeaturesWhy the detail though?• Do you really need the list?Scenario: Listing movies Given I have some movies stored When I browse the list Then I should see the complete collection
    • Amir Barylko - Better Cucumber FeaturesLeaky Scenarios• Each scenario leaves the system in a particular state• The state has to be cleaned up for the next scenario• Otherwise it will “leak” into it• One scenario should not depend on another
    • Amir Barylko - Better Cucumber FeaturesGenerating data• Use a framework to generate valid data• FactoryGirl is a very good option • FactoryGirl.create(:customer) • FactoryGirl.create(:invalid_bank_accout)• Faker will help you to generate fake data
    • Amir Barylko - Better Cucumber FeaturesTransforms• Steps can have arguments• Though regular expression they don’t always show intent• And also we may need to “reuse” them
    • Amir Barylko - Better Cucumber FeaturesSteps with argumentsGiven /^I search for a movie “([^"]*)”$/ do |name| .... # some code hereendGiven /^I have a movie called “([^"]*)”$/ do |name| .... # some code hereend
    • Amir Barylko - Better Cucumber FeaturesCapture the argumentGiven /^I search for a movie “(#{MOVIE_NAME})”$/ do |name| .... # some code hereendMOVIE_NAME = Transform /^([^"]+)$/ do | movie_name | movie_name.downcaseend
    • Amir Barylko - Better Cucumber FeaturesHelpers• Helpers are a great tool to encapsulate common functionality• Or to help describe better our intention• and to avoid looking at ugly code
    • Amir Barylko - Better Cucumber FeaturesCurrent Instance• The World is created for each scenario• Instance variables have to be set• Instead we can use a helper method• to store/create the resource
    • Amir Barylko - Better Cucumber FeaturesHelper Classmodule ProjectHelper def current_project(project = nil) @current_project ||= project end def project_list_page @project_list_page ||= ProjectListPage.new endendWorld(ProjectHelper)
    • Amir Barylko - Better Cucumber FeaturesCustom matchersRSpec::Matchers.define :match_stored_projects do match do |actual| actual == Project.all.map { ... } end failure_message_for_should do |actual| "The projects in the page should match...n" + "The page contains #{actual} n" + "But the storage contains #{@expected}" endend
    • Amir Barylko - Better Cucumber FeaturesPage Objects• The steps rely on the HTML implementation• Searching for elements can be repetitive• or ugly• and not always show intention
    • Amir Barylko - Better Cucumber FeaturesWhat can we do?Then /^I should see the complete list of projects$/ do actual = all(:css, "#projects tbody tr")• .map { |tr| tr.all("td").map(&:text) } .map { |cells| ... } expected = Project.all.map { |p| ... } actual.should == expectedend
    • Amir Barylko - Better Cucumber FeaturesAbstraction!class ProjectListPage include PageObject• def projects all(:css, "#projects tr"). drop(1). #drop the header map { |r| r.all(:css, td).map(&:text) }. map { |r| Project.new(...) } endend
    • Amir Barylko - Better Cucumber FeaturesNicer stepsThen /^I should see the complete list of projects$/ do projects_page.list.should == stored_projects•end Page Object Helper
    • Amir Barylko - Better Cucumber FeaturesWith a custom matcherThen /^I should see the complete list of projects$/ do projects_page.should list_stored_projects•end Custom Matcher
    • Summary
    • Amir Barylko - Better Cucumber FeaturesNext steps• Focus your scenarios on “what” not “how”• Read about scenario outlines• Follow “the Cucumber book” practices• Learn more about page objects pattern• Start with a simple project
    • Amir Barylko - Better Cucumber FeaturesResources• Email: amir@barylko.com,• Twitter: @abarylko• Blog: http://orthocoders.com• Website: http://maventhought.com
    • Amir Barylko - Better Cucumber FeaturesResources II