Do you want your tests fixtures to look like this ?
[TestMethod]
public
void EnterInvalidUsernameAndPassword()
{
//Navigate
to home page
IE
instance = HomePageManager.NavigatetoHomePage();
//Check
that there are no items in the basket
if
(!BasketManager.ValidateBasketIsEmpty(instance))
{
//if not clear it
BasketManager.ClearBasketItems(instance);
}
//Sign
out of the session
SignInManager.SignOut(instance);
//Attempt
a signin with invalid user name
SignInManager.SignIn(instance,
"test&tester.com", "fake", true);
//make
sure that the oops message is visible and the text is correct
Assert.IsTrue(instance.ContainsText("Oops! You made a mistake!"));
Assert.IsTrue(instance.ContainsText("Please enter a valid email address."));
}
In this post I will provide a outline for an approach you can
use to refactor your tests and create a more maintainable and flexible design
to use in your WATiR/N tests.
The WATiR WebRecorder++ and the WATiN WebRecorder++ are great
tools that help create test scripts quickly. In the short term they provide the
ability to create lightweight test scripts by both the developer and the
tester. The recorders output code so
that the user becomes familiar with seeing the language and becomes used to
certain constructs in that language. Once the test script has been recorded,
verification code is written in the form of asserts to ensure that
the required level of functionality is being delivered. Based on these factors,
the creation of test fixtures using WATiR/N is a two-stage process consisting of
recording
and verifying
activities.
With a complex or enterprise web site, the test
fixture starts to get rather large, rather quickly, bringing with it
management and maintainability issues. When creating tests using this
particular approach there are some problems; a large amount of copying and
pasting happens as test fixtures start to overlap; resulting in duplicate code for testing components
that are reused across the site on different pages; and the navigational code for
requesting pages in the site is consistently the same. One way around this is
to provide a template that contains the default actions that your test
fixture requires, record the test and crank out the verification code,
copy this and add the code to the template and stash this away. A simple and
effective way to improve productivity as the main parts of the test are
predefined and heavily tested so if you test script barfs due to coding
errors they are isolated to the new code that has been added to the template,
allowing you to isolate the issue and quickly fix the problem.
The template helps but does not really solve the problems
mentioned above. As a programmer we understand that low coupling and high
levels of cohesion helps to make the code base easier to manage and maintain.
Therefore, why not apply these principles to the test suite. Therefore, I created a design that would
increase cohesion and remove and need to copy and paste code, Don’t Repeat
Yourself (DRY). To implement such a design, there needs to be a separation of
concerns, by breaking away data, processing logic and test
fixture. At this point it is important note that changes to HTML element
id’s can cause your test fixture to break, and there is a question of
responsibility over the tests. One of the reason that
prompted the refactoring of the tests was based on observations that the
developers were not owning the tests. So the tester spent more time maintaining
existing tests rather than creating new tests scripts. For the moment it is
best that we assume all parties are responsible.
Earlier I identified the three areas to be refactored, data,
processing
logic and the tests scripts that we want to rinse.
Here I am going to classify the id’s and names of HTML elements as the data part of the puzzle. Each page on
the site needs to be mirrored to create a test data object, the data objects
are simple property bags containing the id and names of the HTML elements
located on the page. By creating this design, it tackles the issues around
cohesion mentioned earlier. Having all the names and id’s of elements on the
page in one place means that, when there is change on the page updating the variables
happens in one place. The result, of the refactoring means that for each page on
the web site there is a corresponding property bag class that contains the id’s
of HTML elements and a property to access that HTML element.

The simple base structure, contains an abstract class Abstract Page that implements an interface
IPage.
The interface provides the ability to access either a secure or an unsecure web
page. All other data classes that are
created are derived from the AbstractPage class and therefore all
data classes that are created retain the ability to have a secure and unsecure
url’s. To adding a new interface or extending the existing IPage interface you will
be able to add the extra functionality you require. The design is about containment
and isolation, to allow for the auto generation of implemented pages and page
components. The secure and unsecure Url properties are populated from a
configuration file so that you can point the test scripts at a particular
server with ease. A future enhancement that I would like to introduce is the ability
for data classes to be auto generated using a CodeSmith template.
So now that we have meet the data aspect of the design,
we can move on to the reusable logical processing actions of the design. The functionality that is exposed or
expected to be exposed is presented via a manager of the component or page.
Therefore, in the current design there is a manager that you speak with to
perform an action. The manager uses the data objects to access the HTML
elements on the page to perform the task at hand requested. The processing
logic is contained within the manager objects, it is here where you define
common tasks on a page or component. Once there is duplication or common
functionality requirements then this is the place where the code should live.

There is a one to one mapping between the managers and the
page or control. Therefore there is a 1 to 1 mapping between the manager
and the data class, you will notice that each implementation of the manager
class are sealed so that they can’t be extended, they are closed. The next
noticeable facet is that each of the managers are thread safe singletons. The
managers are created from common code or duplicate code found in the outputted
code of the recorder. Such action tasks as, “Login
a user with the correct username and password” or a simple action, “navigate to homepage” make up the
logical processing. These actions are common and are very reusable, achieving
the goal of cohesion and enforcing the separation of concerns that we want from
the pattern. They can also be made into your own toolset of controls that after
a time provide a comprehensive framework. For instance most web sites that
provide a mechanism to order products or service require a login and will have
a shopping basket to order and pay for goods. By adding reusable basket testing
components to your framework will help you become more productive.
[TestMethod]
public
void EnterInvalidUsernameAndPassword()
{
//Navigate
to home page
IE
instance = HomePageManager.NavigatetoHomePage(); //Check
that there are no items in the basket
if
(!BasketManager.ValidateBasketIsEmpty(instance))
{
//if not clear it
BasketManager.ClearBasketItems(instance);
}
//Sign
out of the session
SignInManager.SignOut(instance);
//Attempt
a signin with invalid user name
SignInManager.SignIn(instance,
"test&tester.com", "fake", true);
//make
sure that the oops message is visible and the text is correct
Assert.IsTrue(instance.ContainsText("Oops! You made a mistake!"));
Assert.IsTrue(instance.ContainsText("Please enter a valid email address."));
}
The final piece of the puzzle are the test fixtures When using
the recorder mechanism it can be easy to hit a curve where the QA person is
spending more time doing maintenance tasks rather than creating test
fixtures for the site. These test scripts that are produced can
be confusing and prone to error caused by copy and pasting code from other
areas of the test suite. To provide a solution to this the QA can now write
there tests in a more English notation that can be easily read and understood,
by a BA or developer. How is this achieved? This is done through the using interactions
with the managers of the page and or the managers of component
areas of the site to create a test script for a particular area of
the system. Allowing the QA / tester /
developer to concentrate more on the creation of the test rather than the
maintaining of the test. By designing layers of abstraction test fixtures can build high level readable tests.
The article has covered a mechanism for creating an abstract
test design pattern based on using recorders that are commonly available to the
development and testing teams. The ability of implementing an abstract design
delivers a large amount of reusable code base that can be used on different
projects that you work on, and could even be used as benchmarks for new
projects starting up that have a similar level of functionality.