Total Pageviews

Donate

Feb 21, 2015

Automated UI Testing in Python

During the last year 2014, I was exposed to behavior testing. As I mentioned in my last blog post about agile team building, me and my team applied different automated testing techniques including the behavior testing using Gherkin. In fact, this was - and still - a very hard task to maintain these tests, especially with the unstoppable flow of business changes. Behavior testing is all about complete features and their different scenarios. In other words, it is all about testing the UI being interacted by the system users to apply their business needs. Below I'm going to list why it is not very easy to maintain these tests and after that I will show a new technique that can make it maintainable. But first let's talk a little bit about Selenium and Python Webdriver.

Automating UI Interaction (Selenium) 

Selenium is a web apps software testing framework, and its name came from a joke by the original creator Jason Huggins in an email. He was making a joke of a competitor - Mercury by HP - saying that: "you can cure mercury poisoning by taking selenium supplements" :)
Huggins developed Selenium during 2004 while he was at ThoughtWorks. He joined Google in 2007 completing his work on Selenium. At the same time, ThoughtWorks was working on the development of a browser automation tool called WebDriver. In 2009 these two project has been combined together to produce a new product called Selenium 2.0 or in other words Selenium WebDriver. Now Selenium 2.x is almost the most powerful UI test automation tool and has become a kind of a 'de facto standard' for test automation. Selenium IDE is a Mozella Firefox extension that works as an integrated development environment for Selenium scripts called Selenese. Selenese is a special test scripting language for Selenium.  Selenium Remote Control (RC) is a server written in Java that accepts Selenium command for browser through HTTP. It allows to write automated tests using any programming language that facilitated integrating Selenium in already existing testing frameworks. Selenium client API  is an alternative to writing tests in Selenese that can be written in many languages like Python, Java, C#, and Ruby. Now in Selenium 2, Client API include WebDriver as a central component.
In the following section I'll give an example of how tests can be written using Python Client API.


UI Testing

The following Python code shall start a new Firefox browser, Open Facebook home page and login using the username and password in the code. After the successful login, it simply finds the logout link and clicks it.


Navigating throw the code

The first 4 lines imports the required modules from Selenium Python Client API which is the WebDriver and its different components.

Opening new browser and go to the Facebook home page using line 10, 11. Selecting elements for username and password, and adding the proper values in lines 12 to 15. After clicking login in line 16, the script shall wait using WebDriverWait  until the page is loaded and has element for 'Home' link. This is done in lines 17 to 22. Now it is safe to look for the logout link and click on it in the remaining lines of the code snippet.

Note: If you are protecting your profile with Facebook Code Generator, this script will fail with exception.

This is a very simple and  straight forward example for testing login-logout functionality and it looks like there is nothing wrong with it.
In fact there are 'wrong' things in these very few lines of code.

  • The main issue with this coding style - which is procedural code - is readability. If you want to change the code or if it failed for a reason or another, it would be a nightmare to figure out what to change. In other words, there is no modularity in this style. 
  • This test doesn't have a lot of duplication - in fact it doesn't have any, but when writing more tests in this way you will have much more duplicated selectors and logic to interact with the pages. And as we all know duplicated code is one extremely big obstacle in maintainability.
  • Again all these strings used in selectors are another nightmare for maintainability. What if the developer simply changed the location of the 'Home' link in the DOM of the page. Then all tests depending on clicking on this link - line 19 - will fail and you will have a really hard time in finding out what and where to change!

Testing That Works

Remember; we are writing code to test code and it has to be written with quality!
When we are writing code, we try our hardest to organize everything, and to Don't Repeat Your Self - DRY in your code. So please, apply this to your test code too.

Also there are some design patterns that guide developers / testers to write more maintainable UI tests. Patterns in their nature are platform agnostic and most of the time are not language dependent. The most famous - and in my point of view - practical pattern is the Page Object Pattern.

The idea is to map every page in your web application to a single Page object.
Let's repeat the same simple test written before using this design pattern.
First, I've created a base class for pages called BasePage that might include all initialization and any common behavior for all pages. In this case it only initializes a new Driver.
After that, I created the HomePage class that extends BaseClass and define login and logout functions.

Following are the locators classes which are simply a container for the selectors used by the WebDriver. In this example, we have two locator classes which are HomePageLocators, and HeaderLocators

Now the basic structure is ready to test. The following lines of code do this magic.

By Doing this, we have changed the procedural code into a well structured code, modular, and effectively maintainable. In fact page object has been already integrated in some test frameworks in the .Net Seleno, and Ruby page-object, but unfortunately it is not yet available in Python. Up till the time this article was written, the Selenium  Python Client API official documentation mentioned Page Object pattern and stated that this article and code is not yet complete and they are requesting for contributors and instead they attached a github repository URL for an example written in Python using Page Pattern.

I added all the scripts used in this blog to this github repository where you can download and try them yourself.

1 comment:

  1. This article was inspired by an article written by Mehdi Kalili under the title of Maitainable Automated UI Testing
    Kalili: http://tutsplus.com/authors/mehdi-khalili
    Article: http://code.tutsplus.com/articles/maintainable-automated-ui-tests--net-35089

    ReplyDelete

Donate