Your Automated System Tests Should Be a Joy to Write, Part 3

Now that you're on board with the Page Object pattern, you're wondering how this could possibly get better, right?

There's one more stop on the happy train to System Test Town. We need to go beyond grouping helper methods. It's time to start modeling our application using our system tests.

Page Object Problems

The Page Object pattern starts to get confusing when there are multiple similarly-named pages or screens in your application. For smaller applications, this isn't as much of an issue. If your application is decently large, however, this is more likely. Each area of the application might have a Reports page, for example. If the reports pages have similar sounding names but different functionality, you'll wish you could differentiate them better.

Page Objects also don't help us deal with complicated controls. If you have a grid in your application, for example, you might end up with lots of single purpose methods such as FilterByDocumentNameThenClickDocument and FilterByDocumentAddedDateThenSelect. These methods get the job done; but, they can be hard to sort through (especially if they're not consistently named). They also become a maintenance headache.

Application Modeling

The way to make this better is to start modeling the application in an object-oriented way. Start with the application itself. Create a static class or singleton object that represents the entire application. Let's say you're working on a document management application inspired by your team's unifying love of Guacamole called DocuGuac 2000. Our application model will start with an object called docuGuac. The docuGuac object will have methods that make sense from a whole-application perspective, such as these:

docuGuac.Start() // Starts the application
docuGuac.StatusBarText() // Gets the text from the status bar
docuGuac.Close() // Shuts down the application

The docuGuac object will also contain other objects that let you drill into the functionality of the application. When you're on the Avocadument Document page of the DocuGuac application (as opposed to the Lime Tome page or the Onion Manuscript page) (α), and you want the grid so you can get the row count, you start drilling down from the docuGuac object:

docuGuac.Avocadument.Grid.RowCount


Modeling On-Screen Controls

We also want to continue to build out the functionality of the grid with all the controls and features spelled out as objects and methods. If the grid is very feature rich, we might have a filter control with several controls inside of it. Filtering for documents with "bob" in the document name might look something like this:

docuGuac.Avocadument.Grid.FilterBy("Document Name")
    .FilterValue.SetValue("bob")

Is it verbose? Yes, but it is really for the best. Each step of the way I can see exactly where I am in the application. I don't have to wonder if 'filter value' is giving me a filter off the grid or if it's filtering the list of people in the sidebar. I can see that I am looking at a grid filter on the Avocadument Documents page.

As an added bonus, if I'm using a code editor that isn't completely useless, then I've had autocomplete helping me all the way telling me all the things that I can access on each object. From the Grid, I should be able to see some methods dealing with filters, some methods that will give me rows, a way to get the row count, and any other useful abstractions.


Make It Look Familiar to a User

Let's look again at the sample code above. Note that the FilterBy method takes "Document Name" as the argument. What is "Document Name"? Is it an index of the column? No. Is it some secret attribute of the column that I want to filter? No. It should be the name of the column as it appears on the screen - as it appears to the user. Is it more work to do it this way? Probably. When I write the tool-specific code to get that column filter, I have to find the label with that text "Document Name", read some hidden value off that, then try to match that hidden value to a similar value on the filter. It's extra work, but the goal should be for this model to match the user's experience of the application. A tester shouldn't need to know all the secret hand-shakes to write or understand the automated system tests - even non-coders should be able to understand what's going on. Granted, it will be easier to understand if you are a coder; but, each of these small steps help in the overall understanding and maintainability.

Model your application with your tests. Your test code will be more maintainable and writing the tests will be much easier in the long run.


Notes

α) I'm really sorry about these names. Coming up with a 'good' fake application is really hard. However, I make no apologies for my love of guacamole.

Comments

Popular posts from this blog

A Cold Day in an SUV

Selenium Would Be Awesome If I Didn't Have to Design Around It