story driven development with cucumber

64
Story-Driven Development with Cucumber Sean Cribbs Wednesday, January 6, 2010

Upload: sean-cribbs

Post on 18-Nov-2014

12.310 views

Category:

Technology


0 download

DESCRIPTION

Software projects are rarely on-spec, on-time and on-budget, and the primary cause is miscommunication. As Martin Fowler says, there is a "yawning crevasse of doom" between stakeholders and developers, full of misunderstanding. How do you make sure that you're building something that adds value? How do you know you're building the thing that was asked for? How does your bottom line affect user experience? Into the fray leaps Cucumber, a business-readable DSL combined with an awesome Ruby library that lets domain experts express business requirements as executable user stories. We'll cover outside-in, story-driven development with Cucumber, how to write effective stories, and how to make Cucumber work for your project. (as given to CharlotteRuby on Jan 6, 2010)

TRANSCRIPT

Page 1: Story Driven Development With Cucumber

Story-Driven Development

with Cucumber

Sean Cribbs

Wednesday, January 6, 2010

Page 2: Story Driven Development With Cucumber

who am i

•Freelance Web Consultant

•Radiant Lead Dev

•Ruby, Javascript, Erlang

•Open-source contributor github.com/seancribbs

Wednesday, January 6, 2010

Page 3: Story Driven Development With Cucumber

miscommunication

Wednesday, January 6, 2010

The root cause of so many problems in software projects is miscommunication.

Page 4: Story Driven Development With Cucumber

abstract

Wednesday, January 6, 2010

This is largely because so much of software development is abstract - that is, it happens in your brain. Nontechnical people also have ideas and desires about what software can do that are equally abstract.

Page 5: Story Driven Development With Cucumber

what’s important

Wednesday, January 6, 2010

In the course of a project, it’s often hard to tell what’s really important to its success...

Page 6: Story Driven Development With Cucumber

who said what

Wednesday, January 6, 2010

...and who said what, and why you should care.

Page 7: Story Driven Development With Cucumber

miscommunication=

waste

Wednesday, January 6, 2010

Bottom line, miscommunication is wasteful - in time, money, energy and relationships.

Page 8: Story Driven Development With Cucumber

wrong

Wednesday, January 6, 2010

Miscommunication causes you to build the wrong feature...

Page 9: Story Driven Development With Cucumber

incorrectly

Wednesday, January 6, 2010

... or to build it incorrectly ...

Page 10: Story Driven Development With Cucumber

unnecessarily

Wednesday, January 6, 2010

... or to build unnecessary features.

Page 11: Story Driven Development With Cucumber

“Agile”

Wednesday, January 6, 2010

I bet you’re saying, “hey, aren’t you using an Agile process?” Why yes, I am, thanks. Agile methodologies have a few tools that we can use to help alleviate these miscommunication problems.

Page 12: Story Driven Development With Cucumber

user stories

Wednesday, January 6, 2010

The first is user stories. For any feature that needs to be developed, you create a persona and write a story about how that person will use your software, and what things that person will want to accomplish.

Page 13: Story Driven Development With Cucumber

Test-Driven Development

Wednesday, January 6, 2010

Agile also gives us one of the top buzzes of the Ruby community since its adoption in the West- TDD. TDD encourages us to write tests for our software before we write the software, often resulting in better designs and greater flexibility as the project evolves. So what if we put these two techniques together?

Page 14: Story Driven Development With Cucumber

Story-Driven Development

Wednesday, January 6, 2010

When you do, you get what I call Story-Driven Development. Your agile user stories become the tests for your software. You’ll see more of what I mean in a little bit.

Page 15: Story Driven Development With Cucumber

stay leancreate value

Wednesday, January 6, 2010

The focus of SDD is to keep your software lean and to create value with every new feature.

Page 16: Story Driven Development With Cucumber

minimum to satisfy

Wednesday, January 6, 2010

That is, at each step you’ll be doing the minimum to satisfy the requirements specified by the story...

Page 17: Story Driven Development With Cucumber

make, protect, savemoney

Wednesday, January 6, 2010

...and that story will be designed so that it directly affects your project’s ability to make new revenue, protect existing revenue, control costs, or alleviate user pain and increase utility (basically protecting revenue).

Page 18: Story Driven Development With Cucumber

pop the “why”stack

Wednesday, January 6, 2010

The path to finding the business value in each new feature is to pop the “why” stack.

Page 19: Story Driven Development With Cucumber

who are the stakeholders?

Wednesday, January 6, 2010

That is, the person writing the story will query the business expert who is requesting the feature with pointed “why” questions until the result comes down to money. Along the way, you’ll identify who the stakeholders are and what value they receive. We’ll see more about how this fits into the process later.

Page 20: Story Driven Development With Cucumber

improves communication

Wednesday, January 6, 2010

By expressing the tests for your software first as user stories, you are greatly increasing the ability for the technical people to communicate with the business people. You start to develop a “ubiquitous language” for the problem your software addresses that will assist as the project progresses. See also Eric Evans’ “Domain Driven Design”.

Page 21: Story Driven Development With Cucumber

bridge thecrevasse of doom

Wednesday, January 6, 2010

With story-driven development, you can start to bridge Martin Fowler’s “yawning crevasse of doom” between the developers and the suits.

Page 22: Story Driven Development With Cucumber

living functional spec

Wednesday, January 6, 2010

Your stories become a living functional specification and documentation for your software. Rather than requirements being handed down etched in a stone tablet, the stories become conversation pieces between all parties in the process -- customers, project managers, designers, and developers.

Page 23: Story Driven Development With Cucumber

stories = tests

Wednesday, January 6, 2010

Furthermore, your user stories are executable tests that can be used to verify your software. Hooray for TDD!

Page 24: Story Driven Development With Cucumber

http://cukes.info/

Wednesday, January 6, 2010

So how can you implement this process in a Ruby project? You use Cucumber!

Now what I’ve described before this point is 75% or more of what you’ll do in Story-Driven Development. Cucumber is just a tool to take you the last 25% from concept to implementation. So this next section is going to be a little more about the “how” and not the “why”. But first, more about Cucumber...

Page 25: Story Driven Development With Cucumber

business-readableDSL

Wednesday, January 6, 2010

Cucumber’s first component is a business-readable DSL curiously called “gherkin”. This is a loose format for structuring your user stories so that they will easily translate to executable tests. Note that I didn’t say “business-writable”! The DSL is meant to be written by somebody who works with the biz person, but is also aware of the technical side.

Page 26: Story Driven Development With Cucumber

a Ruby library

Wednesday, January 6, 2010

Cucumber is also, unsurprisingly, a Ruby library that runs the stories as tests against your application.

Page 27: Story Driven Development With Cucumber

integration tests

Wednesday, January 6, 2010

Cucumber stories are intended to exercise your application from top-to-bottom, or more accurately, from the perspective of the user. So if you had to classify them, they’d be considered integration tests.

Page 28: Story Driven Development With Cucumber

Feature: Standard Signup In order to begin using the application As a new user I want to create an account

Scenario: Signup with valid email/password combination Given I do not have an account When I signup with email and password Then I should be logged in And my profile details should be filled in

Wednesday, January 6, 2010

So here’s a pretty typical Cucumber story; this one happens to be about signing up to use the application.

Page 29: Story Driven Development With Cucumber

Feature: Standard Signup In order to begin using the application As a new user I want to create an account

Scenario: Signup with valid email/password combination Given I do not have an account When I signup with email and password Then I should be logged in And my profile details should be filled in

Wednesday, January 6, 2010

The only portions of the story that Cucumber cares about are shown here in bold, so you’re pretty free to write the stories as make sense for the domain. “Scenario” signifies the beginning of a new story, Given/When/Then specify preconditions, user actions, and post-conditions respectively. You can also use “And” or “But” to make your story read well.

Page 30: Story Driven Development With Cucumber

$ cucumberFeature: Standard Signup In order to begin using the application As a new user I want to create an account

Scenario: Signup with valid email/password combination Given I do not have an account When I signup with email and password Then I should be logged in And my profile details should be filled in

1 scenario (1 undefined)4 steps (4 undefined)0m0.754s

Wednesday, January 6, 2010

So let’s execute that story. Cucumber parses the story and attempts to run the Given/When/Then steps that we defined. Since we haven’t written any code yet, all of the steps are pending.

Page 31: Story Driven Development With Cucumber

You can implement step definitions for undefined steps with these snippets:

Given /^I do not have an account$/ do pendingend

When /^I signup with email and password$/ do pendingend

Then /^I should be logged in$/ do pendingend

Then /^my profile details should be filled in$/ do pendingend

Wednesday, January 6, 2010

Now, you were probably wondering how we can implement one of those steps. Well, Cucumber gives us a hint whenever we have unimplemented steps. You can copy and paste any or all of those blocks out of the terminal into your favorite editor.

Page 32: Story Driven Development With Cucumber

Given /^I do not have an account$/ do User.count.should == 0end

Wednesday, January 6, 2010

So let’s implement the first step. Given represents preconditions, so in this case, we’re just doing a paranoid check that there are no registered users. If this statement makes you uncomfortable, don’t worry just yet. Let’s run the story again.

Page 33: Story Driven Development With Cucumber

Feature: Standard Signup In order to begin using the application As a new user I want to create an account

Scenario: Signup with valid email/password combination Given I do not have an account uninitialized constant User (NameError) ./features/step_definitions/signup_steps.rb:2:in `/^I do not have an account$/' features/signup.feature:7:in `Given I do not have an account' When I signup with email and password Then I should be logged in And my profile details should be filled in

Failing Scenarios:cucumber features/signup.feature:6 # Scenario: Signup with valid email/password combination

1 scenario (1 failed)4 steps (1 failed, 3 undefined)0m0.136s

Wednesday, January 6, 2010

Well, it failed, DUH! We haven’t defined the User class yet. So let’s go “down a gear” and implement what we need to make that step pass.

Page 34: Story Driven Development With Cucumber

$ script/generate model User email:string password:string exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/user.rb create test/unit/user_test.rb create test/fixtures/users.yml create db/migrate create db/migrate/20090912024901_create_users.rb$ rake db:migrate db:test:prepare== CreateUsers: migrating =========================-- create_table(:users) -> 0.0016s== CreateUsers: migrated (0.0017s) ================

Wednesday, January 6, 2010

So, since this is a Rails app, we’ll use script/generate to create the User model and migrate the database.

Page 35: Story Driven Development With Cucumber

Feature: Standard Signup In order to begin using the application As a new user I want to create an account

Scenario: Signup with valid email/password combination Given I do not have an account When I signup with email and password Then I should be logged in And my profile details should be filled in

1 scenario (1 undefined)4 steps (3 undefined, 1 passed)0m0.136s

Wednesday, January 6, 2010

Now if we run the story again, we see that the step passed. Before we did that, we might want to write some test/unit tests or RSpec examples to exercise our User model. However - remember we’re always trying to do the minimum amount possible to make the feature pass. If it wasn’t asked for, don’t build it!

Page 36: Story Driven Development With Cucumber

rinse and repeat

Wednesday, January 6, 2010

So once you have created a step matcher, written what needs to be written to exercise the application, and filled in your lower layers of tests, you repeat that process until you get...

Page 37: Story Driven Development With Cucumber

Feature: Standard Signup In order to begin using the application As a new user I want to create an account

Scenario: Signup with valid email/password combination Given I do not have an account When I signup with email and password Then I should be logged in And my profile details should be filled in

1 scenario (1 passed)4 steps (4 passed)0m0.138s

Wednesday, January 6, 2010

... all green! At this point, you would pass the feature to other stakeholders who will evaluate and hopefully approve the work. But let’s first talk about some more of the features that Cucumber gives you that’ll make story-driven development a snap.

Page 38: Story Driven Development With Cucumber

Before do # do before each scenarioend

After do # do after each scenarioend

AfterStep do # do after each Given/When/Then/And/But stepend

Before("@tagged") do # do before scenarios tagged with @taggedend

Wednesday, January 6, 2010

Every testing framework pretty much needs lifecycle hooks, and Cucumber doesn’t disappoint. You can define blocks that will be executed before or after each scenario, after each step, or applied to only specific scenarios or features you have tagged.

Page 39: Story Driven Development With Cucumber

# features/support/time.rbmodule TimeHelpers def set_zone(zone_name) Time.zone = zone_name endend

World(TimeHelpers)

# features/step_definitions/user_steps.rbGiven /^I am in the "([^"]*)" time zone$/ do |zone| set_zone(zone)end

Wednesday, January 6, 2010

One feature I use a lot is to extend the Cucumber “World”, which is the object within which all of your steps execute. Just define a module and pass it to the global “World” method, and then the module’s methods will be available within any step or callback. There are quite a few plugins for Cucumber that use this technique.

Page 40: Story Driven Development With Cucumber

good stories are hard to write

Wednesday, January 6, 2010

So far, I’ve been speaking about how great this process is. But the ugly truth is that good user stories are really hard to write.

Page 41: Story Driven Development With Cucumber

start with the value proposition

Wednesday, January 6, 2010

So how do you begin? You first write the value proposition. This is the most important part of your story and should answer why you need the described feature at all!

Page 42: Story Driven Development With Cucumber

Feature: Name or theme

Wednesday, January 6, 2010

I start by writing “Feature:” and then a descriptive name for the thing that this story will describe, or a vertical aspect of the application that might not have a specific name -- for example, “Admin privileges”.

Page 43: Story Driven Development With Cucumber

Feature: Name or theme In order to make, protect, or save money As a stakeholder I want to have some feature

Wednesday, January 6, 2010

The next part is to “pop the why stack”, identifying the value in the feature. I usually write the value proposition in this three-line format, but there are no restrictions on how you write it. I just find that this format helps me focus on the business value of the feature.

Page 44: Story Driven Development With Cucumber

Feature: School account management In order to maximize revenue by offering our product to multiple schools at once As the site owner I want to provide individual accounts to each school and manage them

Wednesday, January 6, 2010

So here’s an example from an app I worked on earlier this year. We identified the value, who would be taking the action in the story, and what the software would do to provide that value. This story describes a feature of an application for student goal and competency management in primary and secondary schools. [describe the value prop]

Page 45: Story Driven Development With Cucumber

Feature: School account management In order to maximize revenue by offering Schoolbinder to multiple schools at once As the site owner I want to provide individual accounts to each school and manage them

Scenario: List accounts Scenario: Create an account Scenario: Revoke an account Scenario: List admin users for accounts Scenario: Change subdomain for account

Wednesday, January 6, 2010

Next, I create a list of the various things the stakeholder/user can do. Each of these things becomes a scenario within the feature story.

Page 46: Story Driven Development With Cucumber

Feature: School account management In order to maximize revenue by offering Schoolbinder to multiple schools at once As the site owner I want to provide individual accounts to each school and manage them

Scenario: List accounts Then I should see a list of accounts

Wednesday, January 6, 2010

Then you start formulating the scenario. The best way to do this is to write the outcome or “Then” step first, making sure that the desired outcome directly relates to the value proposition stated at the top. In this story, we want to manage school accounts, so seeing a list of the existing accounts would help toward that goal.

Page 47: Story Driven Development With Cucumber

Feature: School account management In order to maximize revenue by offering Schoolbinder to multiple schools at once As the site owner I want to provide individual accounts to each school and manage them

Scenario: List accounts When I go to the accounts page Then I should see a list of accounts

Wednesday, January 6, 2010

After you have the outcome, you decide what action the user takes to achieve that outcome, or the “When” steps. In this case, our user is navigating to the accounts page in our web app.

Page 48: Story Driven Development With Cucumber

Feature: School account management In order to maximize revenue by offering Schoolbinder to multiple schools at once As the site owner I want to provide individual accounts to each school and manage them

Scenario: List accounts Given I am logged in as the site owner When I go to the accounts page Then I should see a list of accounts

Wednesday, January 6, 2010

Finally, you write the preconditions for the user to be able to take that action, or the “Given” steps. We want this functionality only accessible to the site owner and not normal users, so we specify that the user must be logged in as the owner.

Page 49: Story Driven Development With Cucumber

descriptive > imperative

Wednesday, January 6, 2010

So how did I decide to write the story in that fashion? A good rule of thumb to use is that descriptive stories are generally better than imperative stories. Why?

Page 50: Story Driven Development With Cucumber

intention > implementation

Wednesday, January 6, 2010

You want to reveal intention. Your user doesn’t care about how the software is implemented unless they are directly affected.

Page 51: Story Driven Development With Cucumber

# descriptiveWhen I create a new account for "ms218"

# imperativeWhen I follow "New account"And I fill in "Name" with "ms218"And I submit the form

Wednesday, January 6, 2010

Here’s an example from our previous feature of how descriptive steps and imperative steps differ. In the first we’re talking about a holistic action (WHAT), whereas in the second we specify the nitty-gritty detail (HOW).

Page 52: Story Driven Development With Cucumber

descriptive storiesare flexible

Wednesday, January 6, 2010

Descriptive stories are more flexible than imperative stories. Why? The user interface of your software is the most brittle portion - you don’t want your whole suite of tests to break if the designer changes the wording of a single button, link, or field without changing the core functionality of the app.

Page 53: Story Driven Development With Cucumber

strike balancetoo implicit = vague

Wednesday, January 6, 2010

However, you still need to strike a balance. It’s easy to be too vague and have a story cover huge swaths of functionality without intending it. Or the story might be unclear about which of several alternatives to take. Try to be descriptive without being ambiguous.

Also, sometimes, especially early in the story-writing process, it’s a good thing to have imperative stories. When no code has written, when no design has been drawn, having that extra step-by-step may help flesh out more difficult details. You can always go back and rewrite those stories once everyone has a better grasp on the domain.

Page 54: Story Driven Development With Cucumber

avoid conjunctive statements

Wednesday, January 6, 2010

A common “story smell” in features are conjunctive statements. This is best illustrated in an example.

Page 55: Story Driven Development With Cucumber

# conjunctiveWhen I change my name to "Sean" and my password to "foobar"

# independentWhen I change my name to "Sean"And I change my password to "foobar"

Wednesday, January 6, 2010

Conjunctive steps like the first one shown here tend to conflate two separate user actions. Independent steps, however, make the story more readable and the steps reusable within other stories. Remember that we’re trying to develop a ubiquitous language for our domain -- reusability is key to that goal.

Page 56: Story Driven Development With Cucumber

strive for single passes

Wednesday, January 6, 2010

Another “story smell” are multi-pass scenarios, or scenarios where multiple precondition-action-outcome groups occur. These are especially tempting to write if you are thinking imperatively about the problem.

Page 57: Story Driven Development With Cucumber

# conflated scenarios, multiple passes Scenario: Bulk comment on short term goals Given I have set all short-term goals for "ELA > Writing > Organization" for class "601" When I follow "Edit" for long-term goal "Organization" And I follow "Comment" for short-term goal "Coherence" Then I should see all students that pertain to this short-term goal And I should see the standard comment box and "Post new comment" button When I type in the comment box And I follow "Post" Then I should see that my comment was posted

# single scenario, single pass Scenario: Bulk comment on short term goals Given I have set all short-term goals for "ELA > Writing > Organization" for class "601" When post a comment for short-term goal "Coherence" Then I should see that my comment was posted And all students in class "601" should receive my comment

Wednesday, January 6, 2010

The solution to multi-pass scenarios is to split them into multiple scenarios, or to abstract conditions and actions that are covered by another scenario. In this case, we’ve abstracted the concept of posting a comment, encompassing the steps the user took to get to that point. If you’ve already defined the offending steps for other stories, Cucumber lets you call them directly from within another step definition, so you can just subsume the steps that you want to abstract out.

Page 58: Story Driven Development With Cucumber

stay tersecover corner cases

Wednesday, January 6, 2010

Cucumber provides a few more features in the DSL that let you keep your stories terse and cover corner or edge cases efficiently.

Page 59: Story Driven Development With Cucumber

Background: Given an account for subdomain "ms217" And these administrators for subdomain "ms217":

| email | name | | [email protected] | Joe Smith | | [email protected] | Jane Doe | And this welcome message for subdomain "ms217": """ Welcome back, students! - The principal """

Wednesday, January 6, 2010

In this slide I’m showing three of those features. The first is Background, which looks like Scenario, but is defined at the top of a feature file and applies to all of the scenarios in that file -- basically like a “Before” block with multiple steps. The second is a table - which you can access within the definition for the step before the table. You can treat the table as a simple array, or an array of hashes using the headers in the first row. The last feature is a multi-line string or “py_string” (as in Python).

Page 60: Story Driven Development With Cucumber

Scenario Outline: Successful authentication with email Given a <type> named "<first name> <last name>" with email <email> and password "<password>" And I am on the login screen When I login with "<email>" and "<password>" Then I should be logged in

Examples: | type | email | first name | last name | password | | student | [email protected] | Joe | Smith | testing123 | | teacher | [email protected] | Jane | Brown | testing456 | | staff | [email protected] | Mark | White | testing789 | | admin | [email protected] | Paul | Greene | testing098 |

Wednesday, January 6, 2010

Finally, we have Scenario Outlines, which are really great for quickly specifying scenarios across a range of possibilities, including edge or corner cases. Cucumber will run the outline against every row of the table that you specify in the “Examples” section, and apply the values in the table to the angle-bracketed items.

Page 61: Story Driven Development With Cucumber

<self:promotion>

Wednesday, January 6, 2010

So, that’s the overview of Cucumber, and now here comes some shameless self-promotion.

Page 62: Story Driven Development With Cucumber

Wednesday, January 6, 2010

You might have seen that little head in my second slide - which is from our app Lowdown. Lowdown is a collaborative story-writing tool for Cucumber that we created for the Rails Rumble last year, and we were lucky to win the prize for Appearance and User interface. I’d be willing to give a demonstration of Lowdown in the questions period.

Page 63: Story Driven Development With Cucumber

</self:promotion>

Wednesday, January 6, 2010

Now that that’s over...

Page 64: Story Driven Development With Cucumber

questions?

Wednesday, January 6, 2010

Do you have any questions?