Awta2009 Semantic Graffitti
-
Upload
rubytester-testrus -
Category
Technology
-
view
611 -
download
1
description
Transcript of Awta2009 Semantic Graffitti
![Page 1: Awta2009 Semantic Graffitti](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/1.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/2.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/3.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/4.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/5.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/6.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/7.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/8.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/9.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/10.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/11.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/12.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/13.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/14.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/15.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/16.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/17.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/18.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/19.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/20.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/21.jpg)
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](https://reader033.fdocuments.us/reader033/viewer/2022052822/554bc1d0b4c9053a298b51ec/html5/thumbnails/22.jpg)
Thank You
Questions? Tomatos?
http://github.com/marekj/watirloo