Tuesday, 13 January 2015

Getting Off On The Right Foot With Your Test Automation Project Part-3!!!

Approaches For Solving Problems:

All the problems discussed in Part 1 and Part 2 have proven solutions that can help teams get through these challenges. Understanding how to approach these problems is critical to a team’s long term success.

Avoiding Locator Duplication:

Duplication in software explodes complexity and maintenance costs. Avoiding this duplication is critical as you evolve your test suite. It’s especially critical for your element locators. You can’t spend hours tracking down tens or hundreds of duplicate locators when, not if, your UI changes.Many commercial UI automation tools such as Telerik’s Test Studio or HP’s Quick Test Pro handle locator centralization for you. Those tools use variants of a repository to ensure locators are defined only once, with all tests referencing that central element repository in some fashion.Updating the repository ensures all tests get updated locator information as well.

If you’re writing your automation in coded solutions such as WebDriver, Watir, or some other API, then there are a number of approaches to simplify and handle locator definition. Teams
have long used centralized dictionaries to store name/value pairs for locator names and definitions. External settings files have also seen modest success, with each test having to load locators from this external file. Those approaches have worked well in the past; however, over the last three or four years a new approach has gradually evolved: the page object pattern. Page Object Pattern treats each page, or section of a page, as a unique class in code. Properties and methods from the page’s class represent elements and services of the page such as logging on or error messages. The Page Object Pattern
is a natural extension for developers familiar with good object-oriented development. Moreover, the various open source automation APIs have libraries and frameworks that
ease the effort around creating page objects. For example, Jeff Morgan’s Pages gem is a great addition to those writing WebDriver tests in Ruby. WebDriver’s various bindings also

include support for page objects in their native APIs.

Supporting Flexible Locator Strategies

Wherever possible, testers should generally prefer to use ID values for defining element locators. Per the HTML specifications, IDs are unique on a valid HTML page. This
ensures the automation script can quickly locate the desired element simply by scanning the DOM for that ID. It’s fast, it’s extremely flexible.

Unfortunately, some systems may not lend themselves to simple locator strategies. Frameworks and platforms may automate how they create ID values, for example, and they
may do it in a dynamic nature. In such cases it’s often possible for a developer to at least specify a prefix or suffix to the element.

If the developer can do that much, then it’s a snap to create a find logic searching for that unique value. Most commercial automation tools, and several popular open source APIs,
support defining ID-based locators via some form of “ends with,” “begins with,” “contains,” or similar approaches. This allows you to handle situations where a dynamically generated
ID has a unique suffix such as this: ctrl100_ctrl009_div_ctrl300_username.

In some cases you may not be able to use an ID for your locators. You may be working with a legacy UI which wasn’t designed with testability in mind. You may be working in a system which supports multiple widgets on a page, eliminating the ability to have unique IDs on those widgets.

These situations call for alternative approaches. You can look to name or class attributes, or you can carefully craft an XPath expression. Not all XPath is evil! It’s a tool which used wisely can be extremely beneficial. For example, it’s a snap to tie an input field to a neighboring label with XPath. Consider the following figure which shows a logon screen. The associated DOM section is highlighted below it in Firefox’s Firebug.


A simple, flexible XPath expression can be used to define the locator for that input field:

                               //label[text()=’Username’]/../input.

Locator strategies are completely unique to every system simply because each application’s UI is so wildly different from each other. You’ll need to learn how to create good locators in your own environments using the general principles shown in this section.

Solving Positional-Based Locators

In the table example shown earlier, it’s important to not rely on locators hard-wired to a specific row or column. Instead,understand how your particular automation tool or API can interact with the page. Look to create dynamic locators by querying objects to find elements underneath them match
particular criteria.

Here’s a snippet of an example in C# using WebDriver:

IWebElement table = browser.FindElement(By.XPath(“table_id”));
IWebElement targetRow = null;
IList<IWebElement> rows = table.FindElements(By.TagName(“tr”));
foreach (var row in rows)
{
if (row.Text.Contains(“Cobb”))
{
targetRow = row;
}
}

This approach ensures we’re still able to find the target row regardless of where it appears in the table. This block of code would still find the target row if it was in row one or 11.Likewise, clicking the Edit link shouldn’t be dependent on which column it appears in. Given the block above, we can
use a similar approach to find the Edit anchor by querying the target row we’d already located:

        IWebElement editLink =aRow.FindElement(By.LinkText(“Edit”));

Commercial tools offer up similar features, usually both via coded solutions and native tool functionality as well. At the end of the day, you need to understand how your tools or API
work, and leverage those features to ensure you’re crafting great locator strategies.

Resolving Dynamic Content Without Headaches

Locators are the single most important thing to understand in your system; however, dynamic content is a close second. The problem lies in the inability of automation tools to detect when an AJAX call or JQuery event is changing the content of the page. This problem spans all web automation tools from Test Studio to Selenium WebDriver. Events which cause a page load or refresh get handled by all modern automation tools, but the dynamic events are a different issue.

The common, tried-and-proven patter for creating rocksolid tests in dynamic content situations is to use explicit waits for the condition needed by the next step. A great example of this is from Microsoft’s ASP.NET AJAX control toolkit examples. The following figure shows a cascading
menu system. Each menu selection causes an AJAX call back to the server, which returns the items for the following menu based on the choice the user just made.

That tiny little server callback is what causes automation workers serious grief. It’s dynamic, it’s impacted by network conditions, and it’s always slightly different timing. Using explicit waits before interacting with a newly updated element are the key to saving your team’s sanity in these
situations. In the example above, you’d create an explicit wait for the Make dropdown to fully populate with its options, then select the particular option you want for that pass. The Model
option list would get the same treatment: an explicit wait for the exact contents to load, followed by the selection action. This pattern of an explicit wait coupled with an interaction is a
tried, proven strategy for every dynamic content situation. The pattern is the same regardless of whether you’re waiting on content or controls to appear on the DOM, or even an existing
control to change its state (inactive to active, eg).

Implementing waits in your test scripts is completely dependent on the tool or API you’re using. Telerik’s Test Studio uses a Wait step; WebDriver utilizes the WebDriverWait class in the support namespace. Other tools and APIs have similar features. Explicit waits eliminate the frustrating intermittent failures due to synchronization issues around dynamic content.

Helping Maintainability by Supporting Good Design

You’ve seen how good design for storing element locators helps teams create maintainable tests by eliminating duplication around element locator definitions. The same concept of test or method reusability is just as critical to good test case creation. The ability to compose elaborate tests from
smaller building blocks ensures teams aren’t wasting valuable time updating the same functionality across multiple tests when a part of the system’s workflow changes, for example. Design each test such that it’s granular, specific, and doesn’t rely on other test cases first. This enables you to reuse
functionality such as logging on to a system or entering customer data.

Composability and reuse don’t have to be at the page level, either. You can look to break down complex forms into small pieces of functionality designed to handle one specific responsibility such as customer identification, ticketing, etc.Careful reuse of functionality lets you write more accurate,
thorough tests at a much faster rate - and at the same time dramatically decreases maintainability costs.

KEEPING YOUR AUTOMATION SUITES SANE, STABLE, AND MAINTAINABLE

The approaches in this paper aren’t a magic panacea for everyone’s automation woes. UI automation is an incredibly hard problem, and it’s completely different for each application. You’ll have to learn the fundamentals of your application works, and you’re still responsible for ensuring you’re creating solid automation tests. Spend time learning how to get past the basic domain problems like locator strategy, dynamic content synchronization, and support for good test case design. That leaves you more time to focus on the real problem, which is how to deliver more great value to the projects you’re working on.

0 comments:

Post a Comment

 
Back To Top