Showing posts with label Automation. Show all posts
Showing posts with label Automation. Show all posts

Monday, 14 December 2015

Test Tooling Drift - Integration Test Client Anti-Pattern

Test Tooling Drift is a test tool anti-pattern that seems to be a common occurrence on many of the teams that I work with.

In applications with integration points with external systems, clients are usually created in the code to connect with those systems. These clients usually form a part of the code base of the application. They communicate using protocols such as http, tcp, etc.

When testing this type of application, whether its writing automated checks, or creating tools to facilitate testing, you may find teams (test or development) creating their own test clients to handle some of the testing or checking code that is used against those external systems.

An example of this could be a transaction manager that provides transactional capabilities to a payment system. The payment system will have a client that connects to this transaction manager, and there will be a contract between the application client and the transaction system to facilitate functional or technical change. Changes in the contract will usually be handled within the development process of those working on the team. They may even use mechanisms like consumer driven contract tests to facilitate contract change and approval.

In this scenario its common in test tooling to see a separate test client created for the purpose of test being used to communicate with a system such as the transaction manager. As this client is different, if there is a contract change that is implemented between the client in the application, and the transaction manager, there is then room for error to creep into our test client should we not also implement that contract change. The test client has the potential to shield or mask potential issues occurring in contracts, such as protocol issues, network issues, schema issues, etc. This is where drift occurs. Of course, the biggest problem here is the time spent having to keep these clients in sync. We are most definitely violating the DRY principle here.

I've seen this anti-pattern occurring a lot on mobile application projects. Many mobile applications will call an endpoint from the mobile application to facilitate some functionality, and that will be done using a connection client built into the application code. When testing this integration, or running contract tests against this endpoint, you will see tests and checks using tools such as runscope, soapUI, or postman, even though none of these tools and the clients they use to connect to endpoints sit inside your application. Whilst these tests can call the endpoint and validate certain aspects of your contract, they are not doing it in the exact same way as your application client. Inconsistencies are most prominent in request headers, request creation and the deserialization of responses into objects to validate or use within test code.

If you want to reduce risk of failure you should certainly be using the client from the application to make calls to these endpoints during your testing and checking. Tools such as runscope, postman and soapUI are great for investigating and understanding integrations, but they are tools that use their own way to construct requests to your endpoints.

If you are an API provider you might want to make use of consumer driven contract testing to assure you keep alignment with your consumers. Though this can become untenable when you are providing a mass consumed API such as the twitter API, which is when you have to move towards suggesting implementations and best practices for consumers.

Thursday, 27 February 2014

Vagrant - simple environment provisioning

Vagrant is a tool that I'm using more and more these days.
Vagrant provides easy to configure, reproducible, and portable work environments built on top of industry-standard technology and controlled by a single consistent workflow to help maximize the productivity and flexibility of you and your team. 
To achieve its magic, Vagrant stands on the shoulders of giants. Machines are provisioned on top of VirtualBox, VMware, AWS, or any other provider. Then, industry-standard provisioning tools such as shell scripts, Chef, or Puppet, can be used to automatically install and configure software on the machine.
I use it with VirtualBox to quickly install and launch different virtual machines for both development and testing tasks. Some of the teams that I work with have used vagrant within their build process to facilitate test automation or to provide environment consistency in a delivery pipeline.

Its very easy to set up, and is similar for most operating systems
  1. Install VirtualBox
  2. Install Vagrant 
  3. Navigate to where you want to install a vm
  4. Goto a site like http://www.vagrantbox.es/ and choose a prebuilt box 
  5. Then do:
     $ vagrant box add {title} {url}
     $ vagrant init {title}
     $ vagrant up
This will create, initialise and launch the box of your choice in VirtualBox. At point 4, you can just as easily point to your own custom built boxes.

Once you have the box built you can use the following commands to bring up, shut down, or rebuild the box
# to start the box
 $ vagrant up
# to stop the box
 $ vagrant halt
# to rebuild the box
 $ vagrant destroy --force && vagrant up
You can then bring tools like puppet into the equation to manage installations and configurations on the box.

Tuesday, 13 November 2012

Automated smoke tests in production

If you can, don’t be afraid to run your automated tests in production. A production environment is a place where automated tests can give real value, especially after a release. Instant feedback on the success of a change in production could be worth a lot of money to your organisation.

As a minimum run automated smoke tests before and after a release in production, firstly, to baseline, and secondly, to assure nothing has broken after a release.

If you are limited by the data you can use or create during a test then just consider non transactional tests. Any way that you can speed up the feedback loop when a change has occurred is a bonus.

Obviously not all systems or organisations are conducive to this sort of strategy, so as a consideration when building a new system, it’s worth thinking about the ability to run automated tests in a live environment when designing a system.

Wednesday, 28 December 2011

Automate a soap web service using c#

In web service rich systems you can leverage the interfaces that these services provide and test as much of the system as possible. Web Services give you a great opportunity to do quick regression and integration testing of business logic without going through a front end system or creating complicated test harnesses across your system. Automation at this level is extremely valuable to any deployment pipeline.

This quick example shows you how to:
  • Automate a web service with a soap binding using Visual Studio and c# 
  • Set up a simple test framework using NUnit
Automating the web service

For this example we are going to use this banking utility api from http://www.ibanbic.be  that provides several IBAN and BIC conversion facilities. The service uses the soap protocol.

To begin with we need to create a new class library project in visual studio with a references to NUnit. Download NUnit here if you don't have it. You will need to add the following reference  ..\ NUnit-2.5.10.11092\bin\net-2.0\framework\nunit.framework.dll. You may also need to add System.ServiceModel as well.

Once all the references are added we then need to create a c# proxy client class based on the contract (wsdl) of the target web service. We do this using ms svcutil, which you can read more about here.

Once the proxy client class is created add it to the VS project. During the process of creating this proxy client class, an app.config file should have been created as well. Add this to the project.

ProjectName\Services\proxyClient.cs

Invoking the web service

If you don't know how the service works, use a tool like soapUI to interrogate the different requests and responses. This will allow you to become familiar with the data required to be sent with a request, and the expected response.

For this example we are going to invoke the service and use the calculateIBAN1 operation which takes two parameters ISOCountry and account to return an IBAN number.

The code is very simple. I've placed a method inside a class called converters.cs which sits inside a solution folder called modules.



namespace WebServiceAutomationSOAP.Modules
{
    class Converters
    {

        public string CalculateIBAN(string isoCode, string account)
        {

            try
            {
                BANBICSoapClient client = new BANBICSoapClient("IBANBICSoap");
                string iban = client.calculateIBAN1(isoCode, account);
                return iban;
            }
            catch (Exception e)
            {

                return e.ToString();
            }

        }


    }
}


We can now call this method and return either an iban number or an exception.

Setting up the test framework

As with many other examples on this blog, the test framework uses NUnit and separates out business logic from test logic using module classes for business, and test classes for tests. As we saw above we created a module class called converters.cs. Each module class has a corresponding test class.

Create a class called ConverterTests.cs and place it in a solution folder called Tests. Inside this class we will create two tests, one that tests for the correct IBAN creation, and another to check that the correct exception is thrown.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace WebServiceAutomationSOAP
{
    [TestFixture]
    public class Class1
    {

        [SetUp]
        public void SetUp()
        {
     
        // Do some set up configuration here
        }
     
        [Test]
        public testCorrectIBANIsCreatedUsingCalculateIBAN1()
        {

            string expectedIBAN = "IBAN ES44 0000 0333 0000 0000 3434";
            Modules.Converters converters = new Modules.Converters();
            Assert.AreEqual(expectedIBAN, converters.GetIBAN("ES", "000003333434"));

        }


        [Test]
        public testCorrectExceptionIsCreatedWhenIncorrectBankCodeIsUsedWithCalculateIBAN1()
        {

            string expectedException = "This is the expected exception";
            Modules.Converters converters = new Modules.Converters();
            Assert.AreEqual( expectedException , converters.GetIBAN("ES", "cwsaSDFASD"));

        }


        [TearDown]
        public void TearDown()
        {
     
            // Clean up here
     
        }
     
    }
}

Expanding the idea

Once you have this simple test framework in place you can begin to build a suite of tests around a web service very easily. To expand this further you can think about placing the creation of the web service client in the constructor of a base class that can then be inherited by all module classes.

You could also add data driving by using either a constants class, an application configuration file, or a library such as FileHelpers to manage excel or text files.

Of course, soap is not the only webservice type out there. RESTful services have become much more widespread with google, yahoo, twitter adopting these over soap services.  I will give some examples soon of how to automate these!

Thursday, 17 November 2011

Using Selenium WebDriver with C#, NUnit and the Page Object Pattern

In this quick tutorial I am going to show you how to do the following:

  • Set up Selenium Webdriver test project using the C# implementation
  • Use C# and NUnit to build a test framework
  • Use the page object model to build a simple automation test suit
  • Simple data management


Part One - Setting up the project

  • Create a C# .net class library project using the .Net 3.5 framework

    ..\ NUnit-2.5.10.11092\bin\net-2.0\framework\nunit.framework.dll

     ..\net35\*.dll
  • Add a reference to System.Configuration to the project, and the add an application  configuration file

Your solution should like this:



Part Two – Set up a simple test framework using the page object model

Design patterns such as the page object model take the pain out of planning how to manage and set up tests, they also greatly reduce maintenance. I have chosen the page object model as I believe that it is the easiest to understand and gives a robust framework that requires very little, in UI automation terms, maintenance. Read more about automation design patterns here.

For this example I am using a web application I’m working on at the moment, it’s a simple device to manage restaurant table availability. It consists of an account login page and several account utility pages. In this test I have decided to automate the account login page, and the account home page.

Set up some base classes for the project

Create a class called base.cs which will contain all your common variables, objects, methods, etc. For the moment, we just create a new WebDriver instance


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Text;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace Automated
{

    public class Base
    {
        public static IWebDriver driver;
        public static string _baseUrl;
        static Base()
        {
            _baseUrl = ConfigurationManager.AppSettings["baseUrl"];
        }
       
        public void NavigateTo(string url)
        {
            var navigateToThisUrl = _baseUrl + url;
            driver.Navigate().GoToUrl(navigateToThisUrl);
        }
        public void GetDriver()
        {
            //driver = new ChromeDriver();
            driver = new FirefoxDriver();
        }
    }
}

You will notice a reference to the application configuration file we created earlier. In here we are going to put the target url of the application under test. It doesn’t need to go here, but having it here allows us to make this value easily configurable without building a data management framework.

Add the following contents:

  <appSettings>
    <add key="baseUrl" value="http://www.mynewapplication.com" />
  appSettings>


There is also a “navigate to” function. This takes our application base url and tacks on any required paths that we may need to visit directly. We call this method inside the page objects.

For this example I need to create two page object models so I create a class called AccountLogin.cs and AccountHome.cs in a solution folder called Pages. We then model the pages in the classes.

By model, what we are doing is identifying actions and elements on a page and placing them inside a method that can be called on that page object. We may even group together these actions as a part of or full work flow on a page. We may also include in the page object any elements that may serve as assertions.

My two page classes look like this

Pages\AccountLogin.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;
using OpenQA.Selenium;

namespace Automated
{
    public class AccountLogin : Base
    {

        public AccountLogin NavigateToLogin()
        {
            NavigateTo("/account/login");
            return new AccountLogin();
        }
      
        public AccountHome LoginAs(string username, string password)
        {
            driver.FindElement(By.Id("email")).SendKeys(username);
            driver.FindElement(By.Id("password")).SendKeys(password);
            driver.FindElement(By.Id("submit")).Submit();
            return new AccountHome();
        }
    }
}

In the accountlogin page I have modelled the login action (LoginAs). This action fills the login fields and then submits the login form, finally returning the proceeding page, account home. I am using the FindElement method with the field element and submit Ids being used as the identifiers.

Pages\AccountHome

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;

namespace Automated
{
    class AccountHome:Base
    {

       
        public bool User_Welcome_Name(String userFullName)
        {
            IWebElement userWelcome = driver.FindElement(By.ClassName("Welcome");
            bool result = userWelcome.Text.Contains(userFullName);
            return result;
        }
    }
}

In the account home page model, for this example I have identified an object on the page that will tell me if the login has been successful for the user. I have modelled this object as a method that returns a Boolean value, it will return true if the users details that it finds match those that are expected. I am using the FindElement method of Webdriver to locate the text by finding the css classname “Welcome”, I then look in the text to see if the username is contained within.

Bringing the two page objects together as a test

Where possible I try to marry up a test class to a page object, and the actions within that object, for example, the login test class only contains tests that test the login page. It’s similar to functional decomposition only we are breaking an application down into pages. This keeps the testing simple. Sometimes we may also need to introduce workflow testing where we are testing a flow through several pages.

A test class usually contains a Set Up method, one or more tests, and a Tear Down method. The set up method will usually do something like get the webdriver object and make it available to all tests within the class. The Tear Down will usually tidy up the test environment or reset values for the next set of tests. Either of these can be run globally as either a SetUpFixture or TearDownFeature for all tests, or equally, within each test class to be run before and after each test.

A test procedure using selenium requires the following to happen

  1. Instantiate the WebDriver for the browser you wish to automate. This is what we do in the Set Up method, calling the GetDriver method from the base class. This opens up browser specified.
  2. Navigate to a start page. We call the NavigateTo function in the base class to do this. This Method grabs our base url from the app.config file and appends whatever route that we give to the method. See data management below for how to manage different data types such as URLs.
  3. Execute one or more actions, and assert the outcome of those actions.
  4. Tear Down the WebDriver if required, and run clean up commands.

The first test I have written for this example is a successful login test. It navigates to the account login page, fills in the login fields, and submits the login form; it then waits for the account home page to display before executing a checkpoint action to make sure we are on the right page.

The test class looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace Automated
{
    [TestFixture]
    class LoginTests : AccountLogin
    {

        [SetUp]
        public void Setup()
        {
            GetDriver();
            driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 30));
        }

        [Test]
        public void Login_Successful()
        {
            AccountLogin accountLogin = NavigateToLogin();
            // Assert.IsTrue(accountLogin.Sign_Button_Visible());
            AccountHome accountHome = LoginAs("tamgus.bultgreb@yahoo.com", "itsasecret");
            Assert.IsTrue(accountHome.User_Welcome_Name("Tamgus Bultgreb"));

        }

        [TearDown]
        public void TearDown()
        {
            // Some funky stuff here..
        }

    }
}

As you can see, there are some nice hard coded values in the test such as user name and password. These should be extracted out of the test and placed in a test data repository, more about that later.

Running the tests

There are several ways to run the tests, from the command line, with NUnits own UI, or with a test add tool such as test driven. Whilst developing I go for Test Driven as it allows me to run tests quickly from visual studio, but during test runtime, with tests being triggered from a CI server, you need to go down the command line route.

Managing the test data

Your tests will almost always need to have some kind of data to drive them. In the example above we needed to provide a username, a password, and some URLs, we also needed to provide data for some checkpoints.

There are several ways of managing data, each with its own merits, from experience the main mechanisms I have seen successfully used are constant files and datasheets. Constant files are basically static classes that contain all the data that your tests will use assigned to variables. This is a nice way to keep all your test artefacts manageable inside the project. It does mean, though, that data can’t be easily manipulated close to runtime, and if you wish to change data, the test project must be rebuilt. It also stops you from using dynamic data at runtime.

Datasheets give you a lot of flexibility when feeding data into tests, you have the ability to implement different scenarios with the same tests, you can also feed data into your datasheets dynamically, and you can update data at any moment up to the test runtime. However, using datasheets tends to remove some of the robustness of your tests. When you are working with constant files, you are immediately aware of any break in your data, datasheets tend to promote a more “detached” approach to data management which can often lead to incorrect data being used within tests.

When choosing which approach to take you can look at the following

Test flexibility
Data reliability

Test flexibility refers to some of the objectives of your automation efforts. If you wish to have flexibility with the data going into your tests, or you wish a business representative or such to feed in data to your tests, the datasheet route is more favourable. If your data is simple and unchanging, constant files usually give a more stable and robust test project, which should always be one of your main objectives.

Data reliability refers to how “safe” is your data from changing. This is one point that I push more than any in automation. Apart from bad programming, data management is the biggest killer of automation projects. Uncontrollable data will mean lots of failed tests. A good example would not be having complete control over a user in an application, and someone changes the password for that user, or the language that the user sees an application in. This would break your test where you are using either one of those items in the test. In our example above, we have a test called successful login, if someone else has access to the user being used and the data, they could change the password and that successful login test will now fail for data reasons, and not a code bug. This adds to the maintenance debt.

Here is an example of how I can add data values into the base class in the form of constants and use that to drive the tests.

In the base class add test data values to the constructor

public class Base
{
    public static IWebDriver driver;

    public static string _baseUrl, userName, password, userFullName;

    static Base()
    {
        _baseUrl = ConfigurationManager.AppSettings["baseUrl"];
        userName = "livetest999@gmail.com";
        password = "testtest";
        userFullName = "Live Test";        
    }

In the test, you can now reference these values as follows
   
[Test]
public void Login_Successful()
{

    AccountLogin accountLogin = NavigateToLogin();
    Assert.IsTrue(accountLogin.Sign_Button_Visible());
    AccountHome accountHome = LoginAs(userName, password);
    Assert.IsTrue(accountHome.UserWelcomeName(userFullName));

}

If you do go down the datasheet route be prepared to invest time in setting up a data management mechanism in your test suite that can read in and parse data for the tests. Libraries such as FileHelpers can greatly facilitate this.

Ok, that’s it for now. Hopefully you can now set up a test project using the .NET version of WebDriver, implement tests using a common design pattern and implement a simple data management technique. We have not touched upon a lot of UI automation here, just the basics. In the coming months I would like to explore cross browser testing, and localisation testing in more detail.

For more information on NUnit visit their site.

For indepth information on WebDriver visit the Selenium WebDriver Project Wiki.

Saturday, 24 September 2011

UI Automation: Avoiding Failure


I have developed and worked on many UI automation frameworks using both commercial and open source tools, some of these have been more successful than others. Regardless of the tool you use there are some common indicators that you can help you identify if you are going down the wrong path.

No business backed strategy to begin UI automation

UI automation is expensive; it requires a lot of time and effort. Make sure you have enough secured resource to carry out your plans. If you don’t, that resource will be pulled somewhere else and you will end up with several unfinished automation projects that have cost the business money but bring no value.

No clear reason to automate

Why are we automating?  If you have no clear objectives, what’s the point?

Some of the reasons why we should automate
  • to reduce the feedback loop between code implementation and possible defect detection
  • to reduce the amount of time we spend in resource intensive activities such as regression testing
  • to remove human error from test execution

       …and we should automate when:
  • we have stable functionality
  • we have the skill necessary to automate

 No design pattern is being applied to the test design

There is no need to reinvent the wheel with UI automation. Using a recognised design pattern like the page object model will reduce the time it takes to automate. It will also give you cleaner and easier to understand tests. Other engineers will be able to pick up the project and understand it.

Tests are brittle

If small changes to the AUT cause the tests to break then your tests are too brittle and not easily maintainable. 

Things to look out for:

  • Too many checkpoints per test. Always ask yourself what the value of a checkpoint is before implementing it. The more checkpoints we have the greater the chance of test failing. In automation I only test for critical information. Many people will put checkpoints in for page layout, sizing, or styles applied. This is useful but is something that can become hazardous when you start cross browser testing, or testing with different resolutions.
  • Hard coded data. Tests should be driven by a driver class or datasheet if data is required. If you don’t have complete control over your test data then it could change and your tests will break. Being able to feed data in gives you much greater control over the tests and makes them much more useful.
  • Over engineered. Is your test code more complex than the code it is testing? Make sure that your tests are not failing due to over complicated code. I've seen this happen so many times!
  • Tests that depend on the test results of another test. This is a very common mistake. If one test with dependencies fails all dependent tests will also fail.

 No control over the data that drives the tests. When the data changes the tests fail.

Data control is one of the most common reasons why UI automation project fail. Any automation project should have its own environment where data is guaranteed. If the environment is shared then you must have a way of protecting the data your tests use. It’s very frustrating when your data is tampered with and the result is failed tests.

Tests fail because the identification of page or application objects is using ambiguous names, or auto generated identifiers.

UI automation requires us to identify page objects through their properties or location. Many applications will generate unique changing names for objects. Using these names is not secure. Try to get developers to add decent identifiers to objects. It will help keep the tests from becoming brittle and save time during test creation.

Large xpath identifiers are also a common cause of test failure. Try to avoid!

More time is spent on maintaining tests than testing

This is a sure sign you have problems. 

Things to look out for
  • A large number of tests fail on each test run
  • Engineers are “Baby sitting” test runs. Helping the tests complete is not automation!
  • You seem to be spending all your resource on one application. You never get to automate anything else
  • New test creation drops

Nobody knows what the tests coverage is

One thing I’ve found in agile environments is that although UI automation is high on the agenda, there is little understanding of what the test coverage is. Developers and testers churn out tests, get excited, but there is no understanding of what really has been tested. This means that you still have to invest in manual regression runs to assure yourself. UI automation is a safety harness, so we need to know how much protection it is giving us.


Friday, 27 March 2009

When Should We Automate the User Interface in an Agile Environment?

Many misunderstand automation in the context of agile. Picking up a user interface test tool and automating from the word go is never going to work. Automation is often associated directly to UI tests but in an agile environment, automation refers to the whole test strategy. One of our primary goals in agile automation is to develop automated unit tests that will help us monitor the pulse of our project. From there we can look at developing integration tests, coupling together groups of unit tests, or we can look straight to UI automation. UI automation allows us to do both integration and system testing.

In an agile environment we have to look at the real return on investment when deciding what and how we automate in terms of the UI.

Examining the following factors may make this task easier:

1. Risk - A business or safety critical application is always a candidate. Use the other factors to assess the correct moment to automate. Low business impact applications should really be avoided unless work flows are simple.

2. Maturity/Stability - If the web application is still in primary development stages then there will be lots of changes to the UI. Sometimes it is better to wait for a Beta release before beginning UI automation. At this point there will usually be a lower frequency of change or less impacting changes. Waiting until this point saves a lot of time, and reduces the maintenance overhead.

3. Resource - Automation is labour intensive. If you can only devote a small amount of time to UI automation then you are probably not going to have success. Time block an automation project if necessary, it will bring benefit.

4. Change Index - Web applications with a high change index usually require the largest amount of maintenance. Keeping up with a site that has constantly changing layout or content can kill an automation project.

5. Complexity - Large complex systems that use a host of differing technologies, and contain work flows that cross these technologies, should be avoided. Unless, that is, you have the necessary resources and tools to combat this.

6. Technology - If you don't have well supported UI automation tools such as QuickTest Pro or Selenium, or the expertise to use the ones you have got, then your automation project could extend far beyond the original plan. The problem of not having expertise in your automation applications, or even in automation, is that you could find yourself with a very brittle framework that requires constant maintenance, increasing the cost and burden of automation.

Friday, 26 October 2007

Test Automation - Visual Basic Web Automation with IE - Part 3

Finally... Automation

The final part of this series on web application automation will focus on some examples using the concepts discussed in the previous two parts. We shall also discuss some of the limitations of using the DOM and the alternatives available to automate web application testing.

Automating a Web Page

The basic automation of web pages is simple and requires only the combination of the concepts discussed in the first two parts of this series. Before looking in more detail at the examples of automation we need to take into consideration the following DOM limitations mean that not all web pages can be easily automated.

  • Only HTML/DHTML web content can be automated. Web applications based on Java or other development frameworks such as .NET can not always be automated.

  • Web pages are not always developed with automation in mind. It is often necessary to create coding procedures within a development team to include the required properties within the elements to facilitate automation.

Locating Elements

There are various ways in which we can identify elements with the document.

  • Viewing the source code directly.
  • Using a DOM inspector
DOM inspectors are the preferred method as they usually allow the identification of elements by means of clicking on them or hover over them. Source code viewing is effective and can often uncover elements that have not been recognised by a DOM inspector. The only draw back with source code viewing is that it can be time consuming and not always accurate.

Automation

The following examples use Visual Basic Script to automate browser operations.

This function opens a browser and will then navigate to a web page.

Function OpenBrowser(url, sleepTime)
Dim IE
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.Navigate2 url
Do
WScript.Sleep(sleepTime)
Loop while IE.Busy = TRUE
Set OpenBrowser = IE
End Function


A function to click on link.

Function ClickLink( byval oIE, strLnk)
Dim Link
For Each Link In oIE.Document.links
If Instr(strLnk, Link.href) > 0 Then
ClickLink = Link.href
Link.Click
Exit Function
End If
Next
ClickLink = ""
End Function


A basic script that uses the functions OpenBrowser and ClickLink to open up a web page and click on a link.

Set objBrowser = OpenBrowser ("www.google.com", 1000)

Call ClickLink(objBrowser,
http://images.google.com/imghp?tab=wi)

More Methods to access objects in a web page.

Searching on google using the getElementsByName method

Dim IE
Set IE = CreateObject(“InternetExplorer.Application”)
IE.Visible = True
IE.Navigate2 “
http://www.google.com/
Do
WScript.Sleep(1000)
Loop while IE.Busy = TRUE
IE.document.getElementsByName(“q”)(0).value=“Classical Guitar”
IE.document.getElementsByName(“btnG”)(0).click
Set IE=Nothing


Frames - Problems within the DOM

In many cases we find that with an application that contains frames, very often we can’t access the elements inside some of the frames. This is caused by the frame having a different domain to the principal web page, causing access to the DOM of that frame to be denied. This is a security feature that stems from cross frame scripting. It basically stops unwanted access and changes occurring from outside of the domain of the frame; you can read more about it here http://msdn2.microsoft.com/en-us/library/ms533028.aspx. In a development environment developers can be made aware of this and can include the document.domain property to reference the principal domain inside of the frame. This allows access to the frames DOM.

Even though there are limitations to the DOM, there are many other objects such as xml based objects, and methods that can be used to assist us when DOM limitations are reached. A series on test automation frameworks is planned in the near future which will expand on the concepts learned in this series. You will learn how to develop a test automation framework using just VBScript and the API of an application such as Excel.

Conclusion
In this series we have looked at the various concepts involved in the automation of Internet Explorer. We have also described some very basic methods used in web application automation. We now how have a solid base to develop a test harness that takes advantage of these concepts.

For more information on TEST AUTOMATION FRAMEWORKS using VB and Excel. Please contact me through insideSQA.

Test Automation - VBA Web Automation with IE - Part 2

Introduction

In the previous entry of this series we looked at ways of creating the Internet Explorer object and how to interact with the elements contained within that particular object using the DOM. In this entry we will look at the various types of HTML element and some examples of how we can access and manipulate these particular elements.

HTML Elements

How do we interact with the different elements that are described within the DOM? The following examples take the most common elements and demonstrate some of the methods that we can use to access and manipulate them.

Links and Buttons

The following link can be accessed through a wide array of differing methods.

<a href=http://www.brownswood.co.uk name="brownslink" id="brlk" >brownswood</a >

document.Links("brlk").click
document.Links("brownslink").click
document.getElementById("brlk").click
document.getElementsByName("brownslink")(0).click
document.all("brownslink").click
document.all("brlk").click

A button can be accessed using some of the methods above. The properties of the button element below are almost identical to those of the link above.

<INPUT type="button" id=brownsBtn name=brownswood value="Click">

document.getElementById("brownsBtn").click
document.getElementsByName("brownswood")(0).click

Text Boxes

A textbox can have both its value read and set.

<INPUT userProp = "Company" type="text" id="Company Name" name="Company Name" value="Test this text box">

There are various ways to change the value of text box.

document.getElementById(“Company Name”).value=“insideSQA”
document.getElementsByName(“name”)(0).value=“insideSQA”

If the properties name and id are not available then the code below can be used to change its value.

Set Elems= document.getElementsByTagName(“INPUT”)

For each elem in Elems
if elem.userProp=“company” then
elem.value=“insideSQA”
Exit For
end if
Next

List Box

A list box usually contains a number of options that a user can select.

<SELECT size="1" name=“demo_ComboBox">
<option value=“Value 1">Value 1</option>
<option value=“Value 2" >Value 2</option>
<option value=“Value 3" >Value 4</option>
</SELECT>

Set oList=document.getElementsByName(“company type”).item(0)

optionsCount=oList.Options.length
optionOneValue=oList.Options(0).value
optionTxt=oList.Options(0).text

To select one of the options the code below can be used

oList.Options(0).Selected = true
oList.value="value 2"

Checkbox

A checkbox is either checked or unchecked.

<input type="checkbox" name="Company Checkbox">

Set oChkBox=document.getElementsByName("Company Checkbox").item(0)
oChkBox.Checked=True

Radio Button

The radio button element is an array of options where only one option can be selected.

Radio button elements are grouped using the same name.

<input type="radio" name="Company Type" value="Public" checked="checked" />
<input type="radio" name="Company Type" value="Private" />

A radio button is selected by assigning the required value to the object .

Set oRadio=document.getElementsByName(“Company Type”).item(0)
oRadio.checked=True 'This will select Public
oRadio.value="Private" 'This will select Private even if the Publci object node is being pointed to.

Tables

Tables are amongst the most difficult but useful of elements to access. When tables become nested it becomes necessary to work with the child objects of these tables, and sometimes its difficult to identify how many table structures a document contains. A great tool for element identification is the DOM inspector from Mozilla http://www.mozilla.org/projects/inspector/. With this tool it is possible to view all elements in a document, rather like an object spy that you find with a tool like HP's Quick Test Professional.

The table object provides two collections

cells – Access the cells of the table
rows – Access the rows of the table. The rows also allow access to a cells collection to access particular cells present in the row.


Row1 cell1 Row1 cell1
Row2 cell1 Row2 cell1


Access first row and the first column.

Set oTable=document.getElementById(“companyTable”)
oTable.rows(0).cells(0).outerText
oTable.cells(0).outerText

Access second row and the first column.

oTable.rows(1).cells(0).outerText
oTable.cells(2).outerText

Counting Cells and rows

oTable.rows.length
oTable.cells.length
oTable.rows(0).cells.length

Coming up..
Now that the basic concepts are covered we can now look at putting together the various parts to automate a web application. The final part of this series will demonstrate the possibilities of automating html objects within the Internet Explorer Object.

Thursday, 25 October 2007

Test Automation - VB Web Automation with IE - Part 1

Internet Explorer

Internet Explorer is developed using the component object model (COM). This simple fact allows us to write code that can automate many web based applications without the need to invest in expensive automation test tools. Many market leading web automation test tools use the principles that I am going to describe here. In this article, although I am going to describe the use of Visual Basic (VB) in automating many aspects of Internet Explorer, you should note that all these working practices can be easily transcribed to other languages.
VB Development Environments

Throughout this article we will be using visual studio as our VB development environment but you can use any VB development environment. I have at times used the VB editor of MS office to get the work done!

Creating the Internet Explorer COM Object
There are two ways in which we can create the Internet Explorer COM object

- By referring to the Internet Explorer ActiveX library

Dim IE as InternetExplorer.Application
Set IE = New InternetExplorer.Application
IE.Visible = True

- By creating the object using the program identifier (progID) of the COM application.

DIM IE as object
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True

Methods and Properties Available in Internet Explorer

The following list is some of the methods available in Internet Explorer. These methods can be viewed using the object browser that comes integrated with most development environments.

* Navigate2 - Navigates to a specified URL.
* Stop - Aborts the navigation.
* Refresh - Refresh the present URL
* Quit - Closes the browser. Closing a browser while its navigating to some URL is not recommended.
* GoBack - Navigates one page back.
* GoHome - Navigates to home page.
* GoForward - Navigates one page forward.

There are various properties available for use in Internet Explorer. Here is a list of some of the more commonly used properties used when automating web application.

* AddressBar - Controls whether address bar is shown. (Boolean)
* FullScreen - Maximizes window and turns off statusbar, toolbar, menubar, and titlebar. (Boolean)
* LocationName - Gets the short (UI-friendly) name of the URL/file currently viewed. (String)
* LocationURL - Gets the full URL/path currently viewed. (String)
* Path - Returns the path to the application. (String)
* Resizable - Controls whether the window is resizable. (Boolean)
* Silent - Controls if any dialog boxes can be shown. (Boolean)
* Type - Returns the type of the contained document object. (String)
* Visible - Determines whether the application is visible or hidden. (Boolean)
* Busy - Query to see if something is still in progress. (Boolean)
* ReadyState - Describes the current loading state of a page/Object. (Long)

Fundamental Actions

The following sections will demonstrate the use of these methods and properties.
- Browsing to a Web Page or site and waiting for the page to finish loading.

Dim IE

Dim urlStr
urlStr = "www.insideSQA.blogspot.com"
Set IE = CreateObject("InternetExplorer.Application")
IE.Visble = True
IE.Navigate2 urlStr
Do
DoEvents
Loop while IE.Busy = True
Msgbox urlStr & " has now loaded."
IE.Quit
Set IE = Nothing

- Enumerating all open Internet Explorer objects. The following code will form the basis of many of the object recognition techniques used on IE web applications.

Dim IEWins As SHDocVw.ShellWindows
Set IEWin = New SHDocVw.ShellWindows
Dim IEWin
For Each IEWin In IEWins
Msgbox "Name: " & IEWin.Name & vbcr & "LocationURL: " & IEWin.LocationURL
Next
For i = 0 To IEWins.Count - 1
Set IEWin = IEWins.Item(i)
Next

- Closing all open instances of Internet Explorer.

Dim IEWins As SHDocVw.ShellWindows
Set IEWins = New SHDocVw.ShellWindows
Dim IEWin()
ReDim IEWin(1 To IEWins.Count)
Dim i
For i = 1 To IEWins.Count
Set IEWin(i) = IEWins.Item(i - 1)
Next
For i = LBound(IEWin) To UBound(IEWin)
If InStr(1, IEWin(i).FullName, "iexplore.exe", vbTextCompare) Then
IEWin(i).Quit
End If
Set IEWin(i) = Nothing
Next

- Referencing an existing instance of Internet Explorer. This is a useful function as it allows you to work with instances of Internet Explorer that are already existent.

Public Function GetOpenIE(ByVal strUrl As String) As InternetExplorer
Dim insIE As InternetExplorer
Dim shWins As New ShellWindows
For Each insIE In shWins
If insIE.LocationURL Like strUrl Then
Set GetOpenIE = insIE
Exit Function
End If
Next
Set GetOpenIE = Nothing
End Function

Document Object Model

Once the Internet Explorer object is created, we need to access and interact with the objects that the web application consists of, for example, clicking on buttons, selecting web radio buttons, selecting list items, etc... These objects are defined by the html document object model or DOM.
The html DOM is a standard set of objects and includes a standard ways to access and manipulate these objects. All web applications, regardless of the technology or language that they are constructed with, make use of the DOM.
DOM Structure

The html DOM views html documents as a tree structure of elements. It is possible to access and manipulate all elements and their attributes through the DOM tree structure.
Every tag within the html structure of a document is represented as a node. When the tag is accessed or opened, all descendant tags become child nodes of the original starting node.
A tag is a construct that can have various attributes, some maybe pre defined and others may e user defined. In the following example type, value, and name are predefined attributes, and txtVal is a user defined attribute.
INPUT type="textbox" value="Chomsky" name="txtNombre" txtVal="Indepth"

Document

The upper most node in the DOM is the document, this represents the whole document. The document node has no dependant nodes, but provides various collections for different types of html element. It also provides various functions to interact with these elements.
Elements

An element is an object contained within the DOM. Each element has various means of accessing the methods and properties relating to that particular object. Al elements make use of the properties - outerText, innerText, innerHtml, tagName etc...
This piece of VBscript shows a way of accessing a particular text box in a document and changing its value.

Set txtBoxes = documents.GetElementsByName("chomskyTxt")
For i = 0 to txtBoxes.Length - 1
txtBoxes(i).value = "Sky"
next

This is the most common approach we can take when accessing elements of a web page. Using logic and programming structures, we can usually locate all elements within the document and interact with them.

Part 2 of Test Automation - Web Automation with IE will detail the different elements available in Internet Explorer, giving practical examples as how the DOM and VB can be used to access and control automatically a web application.