Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Selenium - The page object pattern


Published on

Slides about the page object pattern with Selenium
Slides slides are courtesy Alex Kogon.

Published in: Software
  • Be the first to comment

Selenium - The page object pattern

  1. 1. The  Page  Object  Pa-ern A  basic  DRY  abstrac-on  pa1ern  for  Web  browser  automa-on  test   development,  maintenance  and  versioning   Alex  Kogon  
  2. 2. Basic  Web  Test  Development • What  do  we  do  in  Selenium  Web  Test  Development?     Just  like  the  user,  we  launch  a  Web  browser,  load  pages,  and  read,   write,  and  click  on  bu1ons  and  links.   • How  do  we  interact  with  the  Web  browser?     The  Web  browser  is  interface  via  an  Object  in  your  code,  which  can   be  told  to  load  pages,  and  queried  for  Element  Objects  that  are   currently  on  the  displayed  Web  page.  These  Element  Objects  may  be   read  from,  wri1en  to,  or  clicked  on.  
  3. 3. A  First  Basic  Selenium  Script 1.  Load   2.  Find  the  search  text  field   3.  Enter  “Alex  Kogon”   4.  Find  the  search  bu1on   5.  Click  on  it  
  4. 4. A  First  Basic  Selenium  Script  (Java) public  class  BasicWebTest  {      private  WebDriver  theSeleniumWebDriver;      @Before      public  void  setUp()  throws  Exception  {          theSeleniumWebDriver  =  new  RemoteWebDriver(new  URL("http://localhost:4444/wd/hub"),  DesiredCapabilities.firefox());      }      @Test      public  void  test()  {          theSeleniumWebDriver.get("");          final  WebElement  myGoogleInputElement  =  theSeleniumWebDriver.findElement(By.cssSelector("#lst-­‐ib"));                myGoogleInputElement.sendKeys("Alex  Kogon");          final  WebElement  mySearchButtonElement  =  theSeleniumWebDriver.findElement(By.cssSelector("#tsf  >  div.tsf-­‐p  >  div.jsb  >  center  >   input[type="submit"]:nth-­‐child(1)"));;      }   }    
  5. 5. Adding  more  searches 1.  Load   2.  Find  the  search  text  field   3.  Enter  other  varia-ons  on  name  (“Alexander  Kogon”,  “Kogon,  Alex”)   4.  Find  the  search  bu1on   5.  Click  on  it  
  6. 6. Another  Search  @Test      public  void  anotherTest()  {          theSeleniumWebDriver.get("");          final  WebElement  myGoogleInputElement  =   theSeleniumWebDriver.findElement(By.cssSelector("#lst-­‐ib"));                myGoogleInputElement.sendKeys("Kogon,  Alex");          final  WebElement  mySearchButtonElement  =   theSeleniumWebDriver.findElement(By.cssSelector("#tsf  >   div.tsf-­‐p  >  div.jsb  >  center  >  input[type="submit"]:nth-­‐ child(1)"));;      }  
  7. 7. Et  cetera…    @Test          public  void  yetAnotherTest()  {              theSeleniumWebDriver.get("");              final  WebElement  myGoogleInputElement  =  theSeleniumWebDriver.findElement(By.cssSelector("#lst-­‐ib"));                    myGoogleInputElement.sendKeys("Alexander  Kogon");              final  WebElement  mySearchButtonElement  =  theSeleniumWebDriver.findElement(By.cssSelector("#tsf  >  div.tsf-­‐p  >  div.jsb  >  center  >   input[type="submit"]:nth-­‐child(1)"));    ;          }      @Test          public  void  andSoAnotherTest()  {              theSeleniumWebDriver.get("");              final  WebElement  myGoogleInputElement  =  theSeleniumWebDriver.findElement(By.cssSelector("#lst-­‐ib"));                    myGoogleInputElement.sendKeys("Kogon,  Alexander");              final  WebElement  mySearchButtonElement  =  theSeleniumWebDriver.findElement(By.cssSelector("#tsf  >  div.tsf-­‐p  >  div.jsb  >  center  >   input[type="submit"]:nth-­‐child(1)"));    ;          }  
  8. 8. Eureka! Isn’t  this  great?       With  almost  no  effort  we  can  write  test  scripts  building  new   func-onality  from  what  we’ve  already  done  by  copying  and  pas-ng  the   exis-ng  work  we’ve  done  and  modifying  a  couple  things.  
  9. 9. So  what’s  the  problem? How  about  if  something  changes?     By  building  a  test  from  an  exis-ng  site  and  copying  the  CSS  selectors,  it   is  easy  to  build  a  large  body  of  func-onality  tests.  However,  what   happens  if  the  CSS  selectors  (or  other  underlying  func-onality)  change?  
  10. 10. Bri-le  Selectors Please  give  us  a  unique  selector!     When  construc-ng  selectors,  there  are  a  variety  of  op-ons  on  how  it  may  be  done.  The   best  selectors  reference  unique  iden-fiers  associated  with  the  HTML  element,  like  the   Google  Search  Text  Field  in  our  example  code:   theSeleniumWebDriver.findElement(By                  .cssSelector("#lst-­‐ib"));   However,  quite  oben  the  developers  have  not  inserted  unique  tags,  and  we  get  a  selector   similar  to  what  we  used  for  the  Google  Search  Bu1on  in  our  example  code:   final  WebElement  mySearchButtonElement  =  theSeleniumWebDriver                  .findElement(By                          .cssSelector("#tsf  >  div.tsf-­‐p  >  div.jsb  >  center  >   input[type="submit"]:nth-­‐child(1)"));  
  11. 11. What  Happens  When  Selectors  Change? Layout  based  selectors  are  a  headache…     Look  at  the  second  selector  again:   cssSelector("#tsf  >  div.tsf-­‐p  >  div.jsb  >  center  >   input[type="submit"]:nth-­‐child(1)"));   With  a  bit  of  knowledge  of  CSS  selectors,  you  can  see  that  this  is  querying  a   subsec-on  of  the  page  for  all  of  it’s  submit  bu1ons,  and  asking  for  the  first  one.   What  if  the  layout  of  the  page  changed,  or  there  was  another  bu1on  inserted   before  it?  Suddenly  either  no  bu1on  will  be  found  or  the  wrong  one  clicked.   Ideally,  the  developers  can  be  convinced  to  insert  unique  selectors  into  every   element  you  need  to  access,  but  oben  this  is  not  the  case.  How  to  handle  the   changes?  
  12. 12. Brute  Force Search  and  Replace     So  let’s  assume  the  guys  at  Google  put  in  another  bu1on  before  the  search  bu1on.  Our   CSS  selector  now  looks  like:   cssSelector("#tsf  >  div.tsf-­‐p  >  div.jsb  >  center  >  input[type= "submit"]:nth-­‐child(2)"));   OK,  well  we’ve  got  four  uses  of  this  selector,  but  they  are  all  in  the  same  file,  so  searching   and  replacing  is  not  the  end  of  the  world.  What  about  if  we  had  hundreds?  And  they  were   in  different  files?     What  if  we  just  had  to  change  it  once?  While  copying  and  pas-ng  code  all  over  is  easy  and   convenient  for  reuse,  it  creates  a  lot  of  extra  busy  work  when  something  needs  to  be   changed.  By  crea-ng  a  “Single  Point  Of  Truth”,  or  a  single  way  in  which  this  selector  is   accessed,  we  only  need  to  change  it  once.  A  bit  of  extra  work  up  front  to  save  a  lot  of  work   in  the  future.  
  13. 13. Don’t  Repeat  Yourself  (DRY) Encapsulate  code  in  a  single  loca-on     OK,  so  we’ve  copied  the  same  code  in  four  places,  and  now  we  need  to  change  it.   To  do  so  most  easily,  we  would  like  to  only  have  to  change  it  once.  What  do  we  do?   Refactor.  One  of  the  most  powerful  innova-ons  in  modern  IDE’s  is  the  ability  to   automa-cally  have  the  IDE  change  code,  a.k.a.  “refactoring”.  Refactoring  allows   you  to  change  the  architecture  of  your  code  on  the  fly,  adop-ng  more  complicated   structures  as  demanded,  while  keeping  things  as  simple  as  possible  at  the  -me.     There  are  several  possible  solu-ons  for  how  to  refactor  this  code  to  be  DRY;  we  will   work  with  extrac-ng  a  common  method  that  is  accessed  from  all  the  tests.  
  14. 14. What  if  the  Selector  is  used  across  mulOple   script  files? Share  methods  within  a  u-lity  class     So  now  we’ve  created  a  single  method  containing  the  CSS  Selector  that   can  be  easily  modified  to  update  the  Selector  when  it  changes.   However,  that  method  is  only  in  one  class.  If  the  selector  is  used  from   mul-ple  test  script  class  files,  the  change  must  be  implemented  in  each   one.  Wouldn’t  it  be  easier  to  just  move  the  method  to  another  class   where  it  could  be  shared  by  all  the  different  test  scripts?   The  “Move”  refactor  is  also  quite  helpful  in  doing  this.  
  15. 15. The  Page  Object  Pa-ern Break  your  u-lity  classes  out  by  Page     The  u-lity  class  we  have  just  created  contains  all  the  logic  to  access   elements  on  the  Web  pages  we  use  in  our  test.  Assuming  there  are   many  Web  pages,  they  are  all  mixed  together  in  our  class.   By  breaking  out  the  u-lity  class  into  separate  classes,  each  with  the   accessors  for  a  single  Web  page,  we  create  a  be1er  abstrac-on  where   we  can  easily  share  func-onality  across  our  test  suite  by  bringing  in   (and  extending)  exis-ng  Page  Object  code  for  each  page  a  test  uses.  
  16. 16. Code   Page  Object  Pa-ern  Architecture Google   Home   Page   Google   Search   Result   Page   Google   Home   Page   Object   Google   Search   Result   Page   Object   Page  Objects Web  Pages Test  1   Test  2   Test  3   Test  Scripts
  17. 17. Maven  and  Page  Objects Store  each  page  as  a  library  in  Maven     Now  that  we’ve  broken  up  our  accessors  into  Page  Objects  so  they  can   be  easily  shared  across  test  scripts,  why  not  put  them  into  a  separate   module  so  that  they  can  be  easily  shared  across  test  projects  as  well?   By  pugng  each  Page  Object  into  a  unique  Maven  module,  tests  can   simply  define  all  the  Page  Objects  they  need  to  reference  in  their   Maven  configura-on  (pom.xml)  file,  and  have  access  to  the  Page   Objects  without  needing  to  copy  the  Page  Objects  into  mul-ple   projects  (another  DRY  viola-on)  or  have  them  all  in  a  single  project.  
  18. 18. Maven,  Page  Objects,  and  Versioning Added  benefits  of  using  Maven     OK,  now  we’ve  encapsulated  each  of  our  CSS  selectors  in  a  single  accessor  method,  stored  each  of   these  in  a  unique  Object  represen-ng  each  Web  page  used,  and  created  a  Maven  library  for  this   Page  Object.  What  next?   When  running  Web  automa-on  tes-ng  in  a  large,  dynamic,  organiza-on,  you  will  find  quite  oben   that  there  are  mul-ple  versions  of  each  Web  page  that  must  be  tested  simultaneously.  Reliability   tes-ng  on  the  live  site  requires  the  version  currently  in  live  is  tested;  integra-on  tes-ng  on   imminent  releases  require  the  version  ready  for  release;  and  development  tes-ng  on  new  versions   of  the  Web  page  (perhaps  a  pipeline  of  mul-ple  future  releases)  require  the  version  for  each  of   those  pages.   Luckily  Maven  already  provides  us  with  a  solu-on.  Maven  libraries  are  easily  versioned  for   deployment,  such  that  many  versions  of  the  library  can  be  available  for  use  by  the  tests  depending   on  which  version  of  each  page  is  to  be  tested.  A  single  test  script  is  s-ll  able  to  be  used  on  the   various  versions,  as  the  differences  in  the  implementa-on  in  each  version  is  abstracted  behind  the   Page  Object.  
  19. 19. Code   Page  Object  Pa-ern  Versioning Google   Home   Page   0.0.1   Google   Home   Page   0.0.2   Google   Home   Page   Object   V  0.0.1   Google   Home   Page   Object   V  0.0.2   Page  Objects Web  Pages Test  1   Test  2   Test  3   Test  Scripts
  20. 20. ConOnuous  Deployment  and  IntegraOon The  full  enchilada     Now  that  we’ve  got  reusable,  versioned  Page  Objects  referenced  from  our  Web  script  code  via   Maven,  and  automated  tests  which  leverage  the  page  objects  by  version,  let’s  see  how  this  works  in   our  Automa-on  solu-ons.   A  Con-nuous  Deployment  and  Integra-on  system  can  be  easily  leveraged  to  provide  tes-ng  across   all  the  mul-ple  versions  in  real  -me.  By  allowing  the  defini-on  of  the  version  of  each  page  to  be   deployed  for  each  tes-ng  to  be  defined,  the  correct  version  of  each  Page  can  be  deployed  into  the   Web  applica-on  servers  for  the  test  run,  and  the  correct  version  of  each  Page  Object  corresponding   to  that  Page  version  used  (by  the  iden-cal  test)  by  dynamically  instruc-ng  Maven  to  use  the  same   version  of  the  Page  Object  that  was  just  deployed  for  tes-ng.   In  this  way  it  is  very  easy  to  test  mul-ple  integra-on  scenarios  in  real  -me  (produc-on,  integra-on,   development,  etc.),  and  to  easily  test  any  possible  integra-on  of  versions  by  simply  defining  the   versions  to  be  used  for  an  Automa-on  run.   Try  doing  that  with  hard  coding.  
  21. 21. ConOnuous  IntegraOon  with  Versioning Jenkins   ConOnuous   IntegraOon   Server Trigger   0.0.1   Build   Checkout   0.0.1   Branch   Git   Version   Control Server Build   0.0.1   Branch   Nexus   Maven   Deployment   Server Tomcat   Web   ApplicaOon   Server Deploy   0.0.1   Branch   Run   0.0.1  Test   Maven   Test Runner Run  With   0.0.1  Page   Object   Selenium   Test  Run   Firefox   Drive   Browser   Deliver   0.0.1  Page   Objects   Deliver   0.0.1   Pages  
  22. 22. ?