{"id":580,"date":"2011-01-25T13:07:59","date_gmt":"2011-01-25T03:07:59","guid":{"rendered":"http:\/\/www.software-testing.com.au\/blog\/?p=580"},"modified":"2023-10-06T09:08:27","modified_gmt":"2023-10-05T23:08:27","slug":"test-automation-styles-and-alternatives-to-the-page-object-pattern","status":"publish","type":"post","link":"http:\/\/www.software-testing.com.au\/blog\/2011\/01\/25\/test-automation-styles-and-alternatives-to-the-page-object-pattern\/","title":{"rendered":"Test automation styles and alternatives to the Page Object pattern"},"content":{"rendered":"<p>Alister Scott has posted some <a href=\"https:\/\/web.archive.org\/web\/20110128175731\/http:\/\/watirmelon.com\/2011\/01\/24\/composition-or-inheritance-for-delegating-page-methods\/\">code examples<\/a> on <a href=\"http:\/\/watirmelon.com\">watirmelon.com<\/a> that show different solutions to a problem that arises for people implementing the Page Object pattern for test automation.<\/p>\n<p>I found Alister&#8217;s approach solutions interesting, because as my automation usually models business\/user goals and\/or domain features\/concepts,\u00a0 I don&#8217;t often have my own page abstraction.\u00a0 See <a href=\"https:\/\/web.archive.org\/web\/20140331054944\/https:\/\/gojko.net\/2009\/10\/06\/putting-selenium-in-the-right-place\/\">http:\/\/gojko.net\/2009\/10\/06\/putting-selenium-in-the-right-place\/ <\/a>for an example of the approach I&#8217;m thinking of.<\/p>\n<p>At the top level might be something like:<\/p>\n<p><code><br \/>\ngoogle=Google.new<br \/>\ngoogle.search(search_phrase)<br \/>\n<\/code><\/p>\n<p>At the next level down, I potentially want to be independent of the user interface, so it doesn&#8217;t make sense to organise around page components.\u00a0 I might have something like:<\/p>\n<p><code><br \/>\ndef search(search_phrase)<br \/>\nenter_search(search_phrase)<br \/>\nsubmit_search<br \/>\n....<br \/>\nend<br \/>\n<\/code><\/p>\n<p>When we get to the third (task) level, this is still at a user or business activity level, so the page model still doesn&#8217;t make sense for me.\u00a0 I&#8217;ll just use the browser driver directly (or my own driver abstraction):<\/p>\n<p><code><br \/>\ndef submit_search<br \/>\nDriver.button(:value, =&gt; \"Google Search\").click<br \/>\nend<br \/>\n<\/code><\/p>\n<p>Yes, I could have another level here such as:<\/p>\n<p><code><br \/>\ndef submit_search<br \/>\nGoogleHomepage.search_button.click<br \/>\nend<br \/>\n<\/code><\/p>\n<p>In most cases though, the task-level UI element has a single purpose, so there&#8217;s not much of an issue with violating DRY. I also try to keep the automation stack as small as possible, so can tolerate a little bit of duplication. Regardless, it&#8217;s easily factored out into a new method if duplication becomes an issue because methods are common to the domain.<\/p>\n<p>I&#8217;ve seen some frameworks that have a really abstract UI driver at the next level (so that they could drive a rich client app, a mobile app and a web app all using the same methods), but I&#8217;ve never needed to do that.<\/p>\n<p>I favour a business\/domain oriented approach because at the business level, the goals and activities don&#8217;t change that much (and I tend to let the automation lag behind my understanding of the problem).\u00a0 It also encourages me to pay attention to the things that matter and be less implementation-focused.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Alister Scott has posted some code examples on watirmelon.com that show different solutions to a problem that arises for people implementing the Page Object pattern for test automation. I found Alister&#8217;s approach solutions interesting, because as my automation usually models business\/user goals and\/or domain features\/concepts,\u00a0 I don&#8217;t often have my own page abstraction.\u00a0 See http:\/\/gojko.net\/2009\/10\/06\/putting-selenium-in-the-right-place\/ [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,30,34,39],"tags":[113,112],"class_list":["post-580","post","type-post","status-publish","format-standard","hentry","category-ruby","category-software-testing","category-test-automation","category-user-experience","tag-automation-style","tag-page-object-pattern"],"_links":{"self":[{"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/posts\/580","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/comments?post=580"}],"version-history":[{"count":8,"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/posts\/580\/revisions"}],"predecessor-version":[{"id":865,"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/posts\/580\/revisions\/865"}],"wp:attachment":[{"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/media?parent=580"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/categories?post=580"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.software-testing.com.au\/blog\/wp-json\/wp\/v2\/tags?post=580"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}