awta2009 semantic graffitti

22
Semantic Watirloo Graffitti My Battles with Watir How I got started Where I went wrong. How I ducktaped my way out of it, sort of... and built Watirloo Framework marekj | testr.us | for ATWA2009

Upload: rubytester-testrus

Post on 08-May-2015

613 views

Category:

Technology


1 download

DESCRIPTION

AWTA 2009 Presentation on Watirloo, a Watir Framework. Page Adapters and UseCase scenario driven runners. Modeling Customer Language in Acceptance Tests

TRANSCRIPT

Page 1: Awta2009 Semantic Graffitti

Semantic Watirloo Graffitti

My Battles with WatirHow I got startedWhere I went wrong.How I ducktaped my way out of it, sort of...

and built Watirloo Framework

marekj | testr.us | for ATWA2009

Page 2: Awta2009 Semantic Graffitti

Huh? The What?

towards the UseCase driven Domain Object Test Modeling, Page Object Human Readable Machine Executable OO Test Notation with a touch of mint.

let's get started at the beginning

require 'watir'ie = Watir::IE.start 'http://bigblabla.com/'ie.text_field(:name, 'ye_id').set 'BubbaJones74'ie.text_field(:name, 'ye_pass').set 'pigscanfly42'ie.button(:value, 'open ye').click

Page 3: Awta2009 Semantic Graffitti

wrap it with meaning

def load_login_page ie.goto 'http://bigblabla.com/'enddef enter_login_info ie.text_field(:name, 'ye_id').set 'BubbaJones74' ie.text_field(:name, 'ye_pass').set 'pigscanfly42'enddef click_login ie.button(:value, 'open ye').clickend#steps to executeload_login_pageenter_login_infoclick_login

Page 4: Awta2009 Semantic Graffitti

and put it in a test harness

require 'test/spec'describe 'user logging to BlaBla awesome app' do it 'presents user with a page' do load_page; ie.title.should == 'BlaBla Login' end it 'lets user enter id and password' do ie.text_field(:name, 'ye_id').exists?.should.be true ie.text_field(:name, 'ye_pass').exists?.should.be true enter_login_info end it 'loads home page when you click login' do click_login; ie.title.should == 'BlaBla HomePage' endend

Page 5: Awta2009 Semantic Graffitti

TaDa! Building a Trap

After 100 tests I realized I have built a trap.I am now concerned with 4 things- managing Browser, Pages and Elements- sequence of events, scenarios - and data sets.- test execution, harness, runtime etc...all of in the same place

Page 6: Awta2009 Semantic Graffitti

Separate Concerns

Pages = Adapter for Watir. Domain Vocabulary for things of concern on the page.

UseCase = Sequence of Events, scenarios, actors, Domain Vocabulary

Scenario Data = Realization of UseCasesTestCases = use the existing frameworks for

execution

Page 7: Awta2009 Semantic Graffitti

Page Adapters

Declare interface as semantic intent mapping to Document Object Model implementation

class Page def initialize(browser) @browser = browser end def semantic_page_object browser.control(:what, how) endendpage = Page.new(ie)page.semantic_page_object.action some_data

Page 8: Awta2009 Semantic Graffitti

Let's try an example

@author = {:first => 'Kurt', :last => 'Vonnegut', :dob => '11/11/1918', :books => ['Slaugherhouse 5', 'Hokus Pocus', 'Mother Night']}

@page = SearchAuthorPage.new do first.set @author[:first] last.set @author[:last] dob.set @author[:dob]end

@page.search

# on a Author search page enter first name, last name and date of birth and click search.

Page 9: Awta2009 Semantic Graffitti

Good Quotes Inspire

"The fundamental principle of Object Oriented programming is the unification of methods and data. Splitting this up inappropriately gets you right back to procedural programming."

Dave Thomashttp://pragprog.com/articles/tell-dont-ask

(there is a chance I misread it)

Page 10: Awta2009 Semantic Graffitti

unify by convention

make hash keys match page objects and set values

@author = {:first => 'Kurt', :last => 'Vonnegut', :dob => '11/11/1918', :books => ['Slaugherhouse 5', 'Hokus Pocus', 'Mother Night']}

@page = [email protected] @author # set the page with data [email protected]

# by convention maps hash keys to methodsdef spray(hashmap) hashmap.each_pair do |page_object, value| page_object.set value endend

Page 11: Awta2009 Semantic Graffitti

Ducktape Watir

I needed RadioGroup, radios sharing the same name

# individual radiosie.radio(:name, 'ze_razio', 'value1')ie.radio(:name, 'ze_razio', 'value2')ie.radio(:name, 'ze_razio', 'value3')

# as a radio_grouprg = ie.radio_group(:name, 'ze_razio')rg.values # => ['value1, 'value2', 'value3']rb.set 2 # => sets second radio in a group

Page 12: Awta2009 Semantic Graffitti

Ducktape Watir

I needed CheckboxGroup, checkboxes that share the same name.

# individual checkboxesie.checkbox(:name, 'ze_shekbochs', 'value1')ie.checkbox(:name, 'ze_shekbochs', 'value2')ie.checkbox(:name, 'ze_shekbochs', 'value3')

# as a checkbox_grouprg = ie.checkbox_group(:name, 'ze_shekbochs')rg.values # => ['value1, 'value2', 'value3']rb.set 2 # => sets second checkbox in a group

Page 13: Awta2009 Semantic Graffitti

Ducktape Watir

RadioGroup is like a Single SelectListCheckboxGroup is like a Multi SelectList

unify Interface to Selectable Control

[SelectList,RadioGroup, CheckboxGroup].each do |control| # set control by item, value, position # query control about item(s), value(s), position(s)end

Page 14: Awta2009 Semantic Graffitti

Moving from Page to Page

That's it with Page ObjectsNow I need to model actor, her behaviour and

value creation in context of a goal

I reach for UseCase object. - provides sequence, recipe, scenarioand default data

Page 15: Awta2009 Semantic Graffitti

UseCase Scenarios

class UseCase attr_accessor :actor, :scenario, :page, :dataset include UseCaseSteps #decorate your usecase def initialize @dataset = some_data_call_to_populate_run @scenario = [:do_that, do_this] end def run @scenario.each {|task| self.send task} endend

usecase = UseCase.newusecase.dataset.update :key => 'value', :bla => 'blabla'usecase.run

Page 16: Awta2009 Semantic Graffitti

UseCases use UseCases

UseCase glues data to pages. Acts like a Gluegun (act_as_gluegun)UseCase is a wrapper for page interactions.The intent is Actor executing a recipe to create

value.UseCase is a TestModel AbstractionUseCase is a holder of needed Domain Objects

holding values that have corresponding Page Object representations. (confused?)

Page 17: Awta2009 Semantic Graffitti

UseCase example

class MarekSchedulesDentistVisit < UseCase attr_accessor :request #my dataset @@scenario = [

:load_dentist_calendar, :find_date_and_time,

:select_date_and_time,:enter_your_personal_info,

:submit_request]end

request={:date=>today,:name=>'marekj',:phone=>testdata[:phone]}usecase = MarekSchedulesDentistVisit.newusecase.request = requestusecase.run

Page 18: Awta2009 Semantic Graffitti

Stack of Abstractions

UseCases can be at different level of abstractionsclass DoTripToTheMoon < UseCase# has method :launch_rocket

class LaunchTheRocket < UseCase# has method :fire_engines

Page 19: Awta2009 Semantic Graffitti

UseCases calling UseCases

def load_dentist_calendar usecase = LoadCalendar.new usecase.runend

def find_date_and_time usecase = FindDateAndTime.new usecase.runend

usecase = MarekSchedulesDentistVisit.newusecase.request = requestusecase.load_dentist_calendarusecase.find_date_and_time# or usecase.run

Page 20: Awta2009 Semantic Graffitti

Maybe Attach Test Framework

You can put UseCase execution in Test Frameworktest/unit, rspec, test/spec, cucumber

require 'test/spec' describe 'requesting dentist appointment' do it 'does not allow to occur in the past' do @usecase = RequestDentistAppointment.new @usecase.request.update :date => yesterday @usecase.run # assert error should be here on submit @usecase.page.title.should == 'I can not has travel machine' endend

Page 21: Awta2009 Semantic Graffitti

About Watirloo

Attempt to make Acceptance Testing written in the language of the Customer's domain propped by UseCase ideas and PageObjects Adapters

Extracted from real world watir frameworks I've implemented for clients: Health Insurance company and Airplane Parts management company.

Page 22: Awta2009 Semantic Graffitti

Thank You

Questions? Tomatos?

http://github.com/marekj/watirloo