29
MATURING YOUR CUCUMBER TEST SUITE Dmitry “D-Shark” Sharkov @DmitrySharkov [email protected]

Dmitry sharkov - Maturing Your Cucumber Suites

  • Upload
    qaoth

  • View
    653

  • Download
    5

Embed Size (px)

Citation preview

Page 1: Dmitry sharkov   - Maturing Your Cucumber Suites

MATURING YOUR CUCUMBER TEST SUITE

Dmitry “D-Shark” Sharkov

@[email protected]

Page 2: Dmitry sharkov   - Maturing Your Cucumber Suites

A UNIVERSAL PROBLEM WITH CODE

from http://www.geardiary.com/2010/09/17/random-cool-stuff-too-many-cats-here-are-a-few-ways-to-organize-them/

It often starts clean, maintainable, and reasonably well thought out.

Page 3: Dmitry sharkov   - Maturing Your Cucumber Suites

A UNIVERSAL PROBLEM WITH CODE

from http://www.examiner.com/article/hoarding-a-misunderstood-disorder

Keeping it that way is hard.

Page 4: Dmitry sharkov   - Maturing Your Cucumber Suites

Test Suites Are Not Immune

Copy-pasting

Overly complex logic

Inconsistent architecture

Rubbish naming

Brittle design

(Technical debt)

from http://www.villageharvestrice.com/2012/08/cucumber-avocado-sushi-rolls/

Page 5: Dmitry sharkov   - Maturing Your Cucumber Suites

In the worst cases, our code can get so cumbersome that working on it stops being fun.

We should take steps to avoid such cases. We can revisit, refactor, and look ahead.

from http://nekozushi.shop-pro.jp/

Page 6: Dmitry sharkov   - Maturing Your Cucumber Suites

Let's look at some ways your Cucumber can start to look like… something else… and how that can be avoided.

from http://laughingsquid.com/how-to-make-a-cucumber-look-like-a-living-slithering-snake/http://cakeheadlovesevil.wordpress.com/2010/03/16/skeleton-cucumber/

Page 7: Dmitry sharkov   - Maturing Your Cucumber Suites

SCENARIOS GONE BADScenario: Successfully submitting payment Given I visit the landing page When I enter my username And I enter my password And I press the login button Then I am authenticated And I see the make a payment link When I click on the make a payment link Then I am on the account details page When I select the pay current balance button And I select today from the payment date calendar And I press the pay now link Then I am on the checkout page When I select credit card from the payment options Then the credit card details dialog appears When I enter my credit card number And I select the expiration date And I enter my cvv number . . .

a million stepscompletely unfocused

not business centric

Page 8: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD SCENARIOS

In the first place, DO NOT write steps to be atomic application interactions.

Given I click the login button And I enter my username And I enter my password And I press enter And I see "Welcome, admin" Given I am an administrator

Given /^I am an administrator$/ do" visit(Home).login_with(user,pass)"end

Don't act as a mouse and keyboard. !Be declarative.

Page 9: Dmitry sharkov   - Maturing Your Cucumber Suites

FIXING BAD SCENARIOS

As a first pass, abstract away the offending steps.Given /^I am an administrator$/ do steps %q{ Given I click the login button And I enter my username And I enter my password And I press enter And I see "Welcome, admin" } end

Then as a second pass, refactor the step definition.

Page 10: Dmitry sharkov   - Maturing Your Cucumber Suites

HOOKS GONE BAD

from http://www.hdwpapers.com/captain_hook_hd_desktop_wallpaper-wallpapers.html

Page 11: Dmitry sharkov   - Maturing Your Cucumber Suites

HOOKS GONE BAD

Tagging these scenarios for traceability and isolation yields @registration!@authentication!@updateProfile!@passwordReset

from http://mysalvagedtreasures.blogspot.com/2010/08/yardstick-makeover-and-yard-sale-finds.html

Suppose we have a website and Cucumber scenarios to test the following: logging in, updating profile, resetting password, registering a new account.

Page 12: Dmitry sharkov   - Maturing Your Cucumber Suites

HOOKS GONE BAD

@registration!@authentication!@updateProfile!@passwordReset!@mobileRegistration!@mobileAuthentication

Things get more complex as the feature set of the application grows. Adding mobile: Adding Facebook integration:

@facebookRegistration @facebookAuthentication!@facebook

Seems reasonable. But look at what can happen to our hooks…

Page 13: Dmitry sharkov   - Maturing Your Cucumber Suites

# trying to avoid collisions with other people running tests"Before('@authentication,@facebookAuthentication," @update,@facebookUpdate') do" create_user_with_random_id_and_fake_email"end!!# need a real email to send password to"Before('@resetPassword,@emailVerification,@updateEmail') do" set_users_email_to_a_known_test_account"end!!# if not regular desktop user then some account fields are empty"Before('@mobileUpdate,@facebookUpdate','~@update') do" clear_fields_for_non_regular_account"end!!Before('@facebookAuthentication,@facebookRegistration') do" remove_password_and_add_facebook_id"end!!Before('@facebook','~@facebookRegistration') do" create_user_with_facebook_specific_fields"end!...

HOOKS HAVE GONE ROGUE • Preconditions become increasingly unclear. !

• Hook interaction becomes difficult to grasp. !

• Tag listings get freaky AND/OR/NOT logic.!

• Feature files don't tell the whole story. !

• Way too many hooks!

Page 14: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD HOOKS

Flip the problem on its head.

Don't figure out what each scenario needs in hooks.rb

Let each scenario TELL you what it needs.

from http://dessertating.wordpress.com/2013/08/13/in-the-words-of-gob-bluth-you-dont-have-time-for-my-illusions/

Page 15: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD HOOKS

@authentication @facebookAuthentication Feature: authentication f Scenario: successful logi When I ...

@registration @emailVerification Feature: verification of Scenario: successful ver When I ...

@authentication @facebookAuthentication @facebookUser @existingUser Feature: authentication f Scenario: successful logi When I ...

@registration @emailVerification @nonrandomUser Feature: verification of Scenario: successful ver When I ...

BEFORE

AFTER

Page 16: Dmitry sharkov   - Maturing Your Cucumber Suites

Before('@randomUser') do @test_user_data[email] = create_random_example_email end # need a real email to send stuff to Before('@nonrandomUser') do @test_user_data[email] = known_test_email_account end Before('@facebookUser') do @test_user_data[email] = known_fb_account_email @test_user_data[facebook_id] = known_fb_account_id @test_user_data[password] = nil end # for all scenarios that require an existing userBefore('@existingUser') do create_user(@test_user_data) end

Page 17: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD HOOKS

With the old approach, adding Google+ integration would have led to adding a new hook and modifying several existing hooks to include or exclude new tags.

With the new approach, all you need is the new hook and these tags for your Google+ scenarios.@googleUser @existingUser

from http://www.dailymail.co.uk/tvshowbiz/article-2024541

Page 18: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD HOOKS

OR…

You can use a Background in the first place and have steps replace the hooks.

Background: google+ user Given I am a Google+ user And I have an existing account

from http://disney.wikia.com/wiki/Peter_Pan_(character)

Page 19: Dmitry sharkov   - Maturing Your Cucumber Suites

STEPS GONE BAD

Given /^I send a nice email to my colleague$/ do @email = Mail.new do body 'Let us partake in brewed beverages after work' from @user.email to '[email protected]' subject 'yo' end @email.deliver! end Given /^I send an angry email to my colleague$/ do @email = Mail.new do body 'I have had it with your shenanigans' from @user.email to '[email protected]'

Not very DRY…

Not very DRY…

Page 20: Dmitry sharkov   - Maturing Your Cucumber Suites

FIXING BAD STEPS

Extract common code into helper methods

module EmailHelpers def send_email (text) @email = Mail.new do body text from @user.email to '[email protected]' subject 'yo' end @email.deliver! end end World(EmailHelpers)features/support/email_helpers.rb

Given /^I send a nice email to my c send_email('Let us partake in bre end Given /^I send an angry email to my send_email('I have had it with yo end

Page 21: Dmitry sharkov   - Maturing Your Cucumber Suites

FIXING BAD STEPS

Rework regexes to reduce the number of definitionsGiven /^I send a nice email to my colleague$/ do send_email('Let us partake in brewed beverages') end Given /^I send an angry email to my colleague$/ do send_email('I have had it with your shenanigans') endGiven /^I send an? (nice|angry) email to my colleague$/ do |style| body = style == 'nice' ? 'Nice code bro' : 'You disgust me' send_email(body) end

Page 22: Dmitry sharkov   - Maturing Your Cucumber Suites

STEPS GONE BAD

Given /^I (?:click|press) (on )?the (.+) (button|link)$/ do | . . . end Given /^I enter "(.+)" (?:in|into) the (.+) $/ do |text, elem . . . end Given /^I see "(.+)"$/ do |text_on_page| . . . end

DRY! However… • Unnecessary layer of abstraction • Everyone has to learn this 'DSL' • Everyone touches this code

Page 23: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD STEPS

Steps should be domain-focused.Given /^I try to reset my password$/ do" # Here put ruby code. watir-webdriver, capybara, page-object." # You have to know one of them anyway."end

Steps should be feature-focused.This means fewer people have to touch the same steps.Testers don't have to keep many available steps in mind.

If Feature files are not used by the business, then you don't need Feature files at all. You can forego the gherkin grammar and write tests directly with ruby.

Page 24: Dmitry sharkov   - Maturing Your Cucumber Suites

INTERACTION GONE BAD

• Pages have lots of elements in common and page objects get repetitive

• Some steps are brutal to get done through a web driver altogether (reading email)

• Some pages are fancy and have custom tags such as <fb:registration/>

gmail.com rendered HTML

Page 25: Dmitry sharkov   - Maturing Your Cucumber Suites

FIXING BAD INTERACTION

Abstract away common elements on pages and use inheritance to bring them in.

require_relative 'base_page_with_navigation'"!class FacebookRegistrationPage < BasePageWithNavigation" page_url(BASE_URL+'/fbregistration')" " text_field(:first_name, :name => 'firstName')" text_field(:last_name, :name => 'lastName')" . . .

Page 26: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD INTERACTION

Go in a different direction when webpages or other clients under test are too nasty.

http://www.veritaslendingsolutions.com/Solutions.aspx

Page 27: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD INTERACTION

Use abstraction for pieces of interactivity besides just screens.class AccountVerificationEmail" attr_accessor :verification_link!! def initialize (browser,text)" @browser = browser" html = Nokogiri::HTML(sanitize_email_text(text))" verification_links = html('.//a[contains(@href,"verifyAcct")]')" @verification_link = verification_links[0]['href']" end"! def click_on_verification_link" if @verification_link != nil then" @browser.goto(@verification_link)" end" end"end

Page 28: Dmitry sharkov   - Maturing Your Cucumber Suites

AVOIDING BAD INTERACTION

Don't forget — you are limited by any technology.

Email doesn't have to be read through a webpage. Step definitions can delegate complex logic to pages objects. There is always a way to make something difficult a little bit easier.

Page 29: Dmitry sharkov   - Maturing Your Cucumber Suites

QUESTIONS & [email protected] @DmitrySharkov

from http://twistedsifter.com/2013/08/surreal-landscapes-made-from-food-carl-warner/