Getting Up to BAT: Designing an Automation Framework
Now that you’ve gotten an automation lead and decided on the browser automation tool you are going to use, the next step is to design an actual automation framework.
This is one of the most critical components of the overall success of your automation strategy, so you will want to make sure you invest properly in this area.
I have seen a large number of automation projects go forth, but each time the critical component determining their success or failure was having a good automation framework.
Solid design and excellent technical resources are absolutely critical to success in this area!
What is an automation framework?
An automation framework is essentially an API that all of your BATs (Blackbox Automated Tests) are written against.
This API can be as simple as the API that is exposed by your browser automation tool (WatiN, Selenium, etc.), but I would highly recommend building your own layer on top of the browser automation tool’s API that will act as a DSL (Domain Specific Language) for automating your application.
Let me break this down a bit further by using an example.
Think about the task of making coffee.
There are several “API” levels we can interact with.
- We can go with a very low level API where we take whole coffee beans and grind them down. Then we take some water, get it hot. We take our filter put the ground beans in it, put it over a cup and pour the water into the filter.
- We can go with a higher level API where we use a traditional coffee maker. In this case we load the coffee maker with a filter, ground coffee beans and water and push a “brew” button. We could also set it to start at a certain time.
- We can go with a very high level API where we use a Keurig machine or similar device. In this case we only make sure the machine has water in it, and we just insert a little pod and press brew. We can make different kinds of coffee, cider or hot cocoa just by changing what pod we use.
Using the API provided by the browser driver is like making the coffee by hand. It’s going to take a large amount of effort each time you do it.
We want our automation framework to be more like the Keurig machine. We want to be able to compartmentalize our tests in little pods that are small and don’t require many hooks into the automation framework.
To rehash this one more time, basically our automation framework will be a framework we build on top of the browser driver framework, which is designed to make it easy to write tests which automate our application.
What makes a good automation framework design?
The true measure of an automation framework is the size of the tests that are written against them. The less lines of code in each test, the better the automation framework captures the domain of the application being automated.
In my earlier post about an example of an automation framework, I talked a bit about the strategy I used in a real implementation of an automation framework.
Here is a diagram showing the different layers. You can see the framework layer is in green here.
You can also see in this diagram that on the right hand side, I have screens, workflows and navigation.
This is one of the common design patterns you can use to build your automation framework, since it closely models that of most web applications.
A good way to design your framework is to use a pattern like this and create classes for each page in your application, create classes which might represent workflows in your application, and create some classes for navigating around the application.
The basic idea you are shooting for with your automation framework is to make it so the tests do not have to know anything about the browser. Only your automation framework itself should be dealing with the DOM and HTML and CSS. Your tests should be dealing with concepts which any user would be familiar with. That is why I commonly use pages and workflows.
Let me give you an example.
Let’s say we ignored the advice of creating an automation framework and decided to program our tests directly against the browser driver layer. In this case, let’s say that we want to automate a login page. Our test might look something like this pseudo-code.
This is not very readable. It is not something an average tester will be able to pick up and start writing, and it is extremely fragile. If you have 500 tests like this and the id changes for one of the elements on the page, many tests will break.
Now, contrast it to this pseudo-code:
Where did all the code go? You don’t need it! Actually it went into the framework, where it can be reused. Now your test code is simple, can be understood by just about anyone, and won’t break with changes to the UI. (You will just have to change the framework method instead of 500 tests.)
If you want some more detailed examples take a look at my Boise Code Camp slides on the subject here.
Let me offer up some general guidelines for creating a good design for an automation framework.
- NEVER require the tests to declare variables.
- NEVER require the tests to use the new keyword or create new objects.
- NEVER require the tests to manage state on their own.
- ALWAYS reduce the number of parameters for API calls when possible.
- ALWAYS use default values instead of requiring a parameter when possible.
- PREFER to make the API easier to use over making the internals of the API less complex.
- PREFER using enumerations and constants to requiring the test to pass in primitive types. (Make the input bounded when possible.)
- NEVER expose the browser or DOM to the tests or let them manipulate it directly.
You can see that these guidelines will almost force your API to be entirely static methods! Don’t freak out. It is perfectly fine. There is nothing wrong with using static methods in this case.
Stop… take a breath, think about why you think static methods are bad, because I probably agree with you.
But, in this case we are HIGHLY valuing making the tests simple and easy to write over anything else, and because of this emphasis, static methods are going to be the way to go.
Some advice on getting started
Start with the tests in plain human English.
Take those tests and make them into code preserving as much English as possible. Then work down from there implementing the methods needed to make those tests work. Only add things as you need them. Do not overdesign!
In my example above, we might have started with something like this:
- Goto the login page.
Login with the default user.
The actual code looks just like that. It should always be a 1 to 1 mapping.
This is where having someone that has some experience doing this is going to come in handy.
Just keep in mind the whole time your 2 big goals:
- Easy to write tests
- Tests are concise