Awta2009 Semantic Graffitti

Uploaded on

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

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

More in: Technology , Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads


Total Views
On Slideshare
From Embeds
Number of Embeds



Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

    No notes for slide


  • 1. 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 | | for ATWA2009
  • 2. 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 '' ie.text_field(:name, 'ye_id').set 'BubbaJones74' ie.text_field(:name, 'ye_pass').set 'pigscanfly42' ie.button(:value, 'open ye').click
  • 3. wrap it with meaning def load_login_page ie.goto '' end def enter_login_info ie.text_field(:name, 'ye_id').set 'BubbaJones74' ie.text_field(:name, 'ye_pass').set 'pigscanfly42' end def click_login ie.button(:value, 'open ye').click end #steps to execute load_login_page enter_login_info click_login
  • 4. 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? true ie.text_field(:name, 'ye_pass').exists? true enter_login_info end it 'loads home page when you click login' do click_login; ie.title.should == 'BlaBla HomePage' end end
  • 5. 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
  • 6. 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 UseCases
    • TestCases = use the existing frameworks for execution
  • 7. 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) end end page = page.semantic_page_object.action some_data
  • 8. Let's try an example @author = {:first => 'Kurt', :last => 'Vonnegut', :dob => '11/11/1918', :books => ['Slaugherhouse 5', 'Hokus Pocus', 'Mother Night']} @page = do first.set @author[:first] last.set @author[:last] dob.set @author[:dob] end # on a Author search page enter first name, last name and date of birth and click search.
  • 9. 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 Thomas
    • (there is a chance I misread it)
  • 10. 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 = @page.spray @author # set the page with data parameters # by convention maps hash keys to methods def spray(hashmap) hashmap.each_pair do |page_object, value| page_object.set value end end
  • 11. Ducktape Watir
    • I needed RadioGroup, radios sharing the same name
    # individual radios, 'ze_razio', 'value1'), 'ze_razio', 'value2'), 'ze_razio', 'value3') # as a radio_group rg = ie.radio_group(:name, 'ze_razio') rg.values # => ['value1, 'value2', 'value3'] rb.set 2 # => sets second radio in a group
  • 12. Ducktape Watir
    • I needed CheckboxGroup, checkboxes that share the same name.
    # individual checkboxes ie.checkbox(:name, 'ze_shekbochs', 'value1') ie.checkbox(:name, 'ze_shekbochs', 'value2') ie.checkbox(:name, 'ze_shekbochs', 'value3') # as a checkbox_group rg = ie.checkbox_group(:name, 'ze_shekbochs') rg.values # => ['value1, 'value2', 'value3'] rb.set 2 # => sets second checkbox in a group
  • 13. Ducktape Watir
    • RadioGroup is like a Single SelectList
    • CheckboxGroup 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
  • 14. Moving from Page to Page
    • That's it with Page Objects
    • Now I need to model actor, her behaviour and value creation in context of a goal
    • I reach for UseCase object.
    • - provides sequence, recipe, scenario
    • and default data
  • 15. 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} end end usecase = usecase.dataset.update :key => 'value', :bla => 'blabla'
  • 16. 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 Abstraction
    • UseCase is a holder of needed Domain Objects holding values that have corresponding Page Object representations. (confused?)
  • 17. 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 = usecase.request = request
  • 18. Stack of Abstractions
    • UseCases can be at different level of abstractions
    • class DoTripToTheMoon < UseCase
    • # has method :launch_rocket
    • class LaunchTheRocket < UseCase
    • # has method :fire_engines
  • 19. UseCases calling UseCases def load_dentist_calendar usecase = end def find_date_and_time usecase = end usecase = usecase.request = request usecase.load_dentist_calendar usecase.find_date_and_time # or
  • 20. Maybe Attach Test Framework
    • You can put UseCase execution in Test Framework
    • test/unit, rspec, test/spec, cucumber
    require 'test/spec' describe 'requesting dentist appointment' do it 'does not allow to occur in the past' do @usecase = @usecase.request.update :date => yesterday # assert error should be here on submit == 'I can not has travel machine' end end
  • 21. 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.
  • 22. Thank You Questions? Tomatos?