Test automation styles and alternatives to the Page Object pattern
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’s approach solutions interesting, because as my automation usually models business/user goals and/or domain features/concepts, I don’t often have my own page abstraction. See http://gojko.net/2009/10/06/putting-selenium-in-the-right-place/ for an example of the approach I’m thinking of.
At the top level might be something like:
google=Google.new
google.search(search_phrase)
At the next level down, I potentially want to be independent of the user interface, so it doesn’t make sense to organise around page components. I might have something like:
def search(search_phrase)
enter_search(search_phrase)
submit_search
....
end
When we get to the third (task) level, this is still at a user or business activity level, so the page model still doesn’t make sense for me. I’ll just use the browser driver directly (or my own driver abstraction):
def submit_search
Driver.button(:value, => "Google Search").click
end
Yes, I could have another level here such as:
def submit_search
GoogleHomepage.search_button.click
end
In most cases though, the task-level UI element has a single purpose, so there’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’s easily factored out into a new method if duplication becomes an issue because methods are common to the domain.
I’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’ve never needed to do that.
I favour a business/domain oriented approach because at the business level, the goals and activities don’t change that much (and I tend to let the automation lag behind my understanding of the problem). It also encourages me to pay attention to the things that matter and be less implementation-focused.
Thanks for a good write up on this.
I personally don’t like “really abstract UI driver at the next level” (a la Capybara) either, because I find them frustratingly limiting.
I know you don’t like Cucumber, but I am using Cucumber a lot and I find it’s easy to link cucumber scenarios to cucumber steps to page objects, but I am keen to give your business/domain/goal/activity approach a try, but I need to give it some time so I can think through how to best implement it, whether it be modules in ruby, or classes, or something else entirely.
Any suggestions or ideas?
I’ve not used Capybara, but taking a quick look at what it does, it’s not really what I’m talking about when I talk about abstract UI driver.
An abstract UI driver would let me do something like –
control.set_value(true)
The control could be a select list, a radio button, a checkbox or a text field. The point would be that it provides a more abstract interface to the control so that we can modify the UI without having to go and update all of our tests with control-specific information.
I’ve not really had a need to do this, but I’m aware of commercial tools that provide such a framework, and I vaguely recall Elisabeth Hendrickson demoing an approach at STANZ that would let you do something like it.