Awta2009 Semantic Graffitti


Published on

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

Published in: Technology, Education
  • 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

No notes for slide
  • Awta2009 Semantic Graffitti

    1. 1. Semantic Watirloo Graffitti <ul><li>My Battles with Watir </li></ul><ul><li>How I got started </li></ul><ul><li>Where I went wrong. </li></ul><ul><li>How I ducktaped my way out of it, sort of... </li></ul><ul><li>and built Watirloo Framework </li></ul><ul><li>marekj | | for ATWA2009 </li></ul>
    2. 2. Huh? The What? <ul><li>towards the UseCase driven Domain Object Test Modeling, Page Object Human Readable Machine Executable OO Test Notation with a touch of mint. </li></ul><ul><li>let's get started at the beginning </li></ul>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. 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. 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. 5. TaDa! Building a Trap <ul><li>After 100 tests I realized I have built a trap. </li></ul><ul><li>I am now concerned with 4 things </li></ul><ul><li>- managing Browser, Pages and Elements </li></ul><ul><li>- sequence of events, scenarios </li></ul><ul><li>- and data sets. </li></ul><ul><li>- test execution, harness, runtime etc... </li></ul><ul><li>all of in the same place </li></ul>
    6. 6. Separate Concerns <ul><li>Pages = Adapter for Watir. Domain Vocabulary for things of concern on the page. </li></ul><ul><li>UseCase = Sequence of Events, scenarios, actors, Domain Vocabulary </li></ul><ul><li>Scenario Data = Realization of UseCases </li></ul><ul><li>TestCases = use the existing frameworks for execution </li></ul>
    7. 7. Page Adapters <ul><li>Declare interface as semantic intent mapping to Document Object Model implementation </li></ul>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. 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. 9. Good Quotes Inspire <ul><li>&quot;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.&quot; </li></ul><ul><li>Dave Thomas </li></ul><ul><li> </li></ul><ul><li>(there is a chance I misread it) </li></ul>
    10. 10. unify by convention <ul><li>make hash keys match page objects and set values </li></ul>@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. 11. Ducktape Watir <ul><li>I needed RadioGroup, radios sharing the same name </li></ul># 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. 12. Ducktape Watir <ul><li>I needed CheckboxGroup, checkboxes that share the same name. </li></ul># 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. 13. Ducktape Watir <ul><li>RadioGroup is like a Single SelectList </li></ul><ul><li>CheckboxGroup is like a Multi SelectList </li></ul><ul><li>unify Interface to Selectable Control </li></ul>[SelectList,RadioGroup, CheckboxGroup].each do |control| # set control by item, value, position # query control about item(s), value(s), position(s) end
    14. 14. Moving from Page to Page <ul><li>That's it with Page Objects </li></ul><ul><li>Now I need to model actor, her behaviour and value creation in context of a goal </li></ul><ul><li>I reach for UseCase object. </li></ul><ul><li>- provides sequence, recipe, scenario </li></ul><ul><li>and default data </li></ul>
    15. 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. 16. UseCases use UseCases <ul><li>UseCase glues data to pages. </li></ul><ul><li>Acts like a Gluegun (act_as_gluegun) </li></ul><ul><li>UseCase is a wrapper for page interactions. </li></ul><ul><li>The intent is Actor executing a recipe to create value. </li></ul><ul><li>UseCase is a TestModel Abstraction </li></ul><ul><li>UseCase is a holder of needed Domain Objects holding values that have corresponding Page Object representations. (confused?) </li></ul>
    17. 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. 18. Stack of Abstractions <ul><li>UseCases can be at different level of abstractions </li></ul><ul><li>class DoTripToTheMoon < UseCase </li></ul><ul><li># has method :launch_rocket </li></ul><ul><li>class LaunchTheRocket < UseCase </li></ul><ul><li># has method :fire_engines </li></ul>
    19. 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. 20. Maybe Attach Test Framework <ul><li>You can put UseCase execution in Test Framework </li></ul><ul><li>test/unit, rspec, test/spec, cucumber </li></ul>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. 21. About Watirloo <ul><li>Attempt to make Acceptance Testing written in the language of the Customer's domain propped by UseCase ideas and PageObjects Adapters </li></ul><ul><li>Extracted from real world watir frameworks I've implemented for clients: Health Insurance company and Airplane Parts management company. </li></ul>
    22. 22. Thank You Questions? Tomatos?