Selenium – Extend Web Driver to Automate UI Testing

Selenium is a browser based testing automation framework. It is very simple to use and straight forward, all you need to do is download Selenium IDE for Firefox, and execute the test case and record the steps. Once recorded, it can be executed as may times as you want, simple!! You don’t need a tester after first execution 😉

However, Topic of discussion here is NOT Selenium Browser based automation. I am going to talk about using Selenium Web Drivers to extend NUnit testing framework to Automate execution of test cases in an integration environment, basically, execute UI test cases using web driver.

Getting Started

I’ll talk about creating an API that can be used with Web application and/or Windows application. To start with, you need to have a complete understanding of Selenium. Below are the components that we would write to complete this API.

  1. SeleniumCore – .NET C# Class Library to extend Selenium WebDriver.
  2. Services – Class library to interact with test-case repository.
  3. API – Windows Console Application.

How it Works

The selenium web driver is basically to execute NUnit test cases – or to execute unit tests, however, the aim here is to use it for executing integration test cases. Though it is not possible to completely automate SIT cases, we can automate re-occurring test cases. Basically all test cases that do not require data validation can be automated. I’d not rely on this to have complete SIT done, rather I’d use this to do a Smoke Test in SIT environment post major deployments. We would use the Web Drivers from Selenium to invoke browser and execute test cases. We will use Webdriver to execute test cases (NUnit) stored in database or we will get parameters from database to load web-pages and validate elements on page. We will also incorporate features like taking screenshot of valid test case execution.

Let’s Start

Let us write a custom Selenium engine to use Webdriver to execute test case. We will take the webdriver(IWebDriver) and create an instance of it. We will use Internet Explore to execute all our test cases as it is one of the most common browsers. To use IE, we need to download and copy the driver to application “bin” folder and ensure that it is available there. Download Selenium Internet Explorer driver from here.

Create an Instance of Internet Explorer Driver

Create a singleton instance of selenium internet explorer driver.

    public sealed class InternetExplorer
    {
        private static volatile IWebDriver instance;
        private static object syncRoot = new object();

        private InternetExplorer() { }

        public static IWebDriver Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new InternetExplorerDriver(new InternetExplorerOptions() { IntroduceInstabilityByIgnoringProtectedModeSettings = true });
                    }
                }
                return instance;
            }
        }
    }

Search Based on Link Text

Selenium allows you to search or execute test case using various elements on an html/aspx page. When I say elements on a page, it is, Link Text, Element Id, CssClass Name, attributes and so on.. Basically html tags/elements. Selenium web driver can look for a particular text n an element – this search is run on a response when a URL is streamed. If the Link Text/Search criteria fails, web driver throws an exception with specific text indicating that search failed/test case failed.

    public class LinkText
    {
        private List<Results> results { get; set; }

        public LinkText()
        {
            results = new List<Results>();
        }

        /// <summary>
        /// Search based on link text
        /// </summary>
        /// <param name="searchOptions"></param>
        /// <returns></returns>
        public List<Results> Search(Options searchOptions)
        {
            var dbTestCase = new SeleniumExtension.Services.MockSqlServices().GetSimpleDataObjects();
            foreach (var item in dbTestCase)
            {
                InternetExplorer.Instance.Navigate().GoToUrl(item.Url);
                foreach (var keyword in item.Keywords)
                {
                    try
                    {
                        IWebElement search = InternetExplorer.Instance.FindElement(By.LinkText(keyword));
                        results.Add(new Results()
                        {
                            Keyword = keyword,
                            Status = "Pass",
                            Url = item.Url
                        });
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message.Contains(String.Format("Unable to find element with link text == {0}", keyword)))
                        {
                            results.Add(new Results()
                            {
                                Keyword = keyword,
                                Status = "Fail",
                                Url = item.Url
                            });
                        }
                    }

                    if (searchOptions.TakeScreenShot)
                    {
                        Features.TakeScreenshot.Snap(InternetExplorer.Instance, Utilities.Utilities.GetFileName(item.Url));
                    }
                }
            }
            return results;
        }
    }

Selenium features

Selenium offers various features, one of them is implemented here, to take screenshot. Here, I’ve extended the webdriver and made use of the selenium screen shot feature to take pages while executing the WebDriver.

    public class TakeScreenshot
    {
        public static void Snap(IWebDriver driver, string fileName)
        {
            ITakesScreenshot screenShotDriver = driver as ITakesScreenshot;
            Screenshot screenShot = screenShotDriver.GetScreenshot();
            var parentFolder = AppDomain.CurrentDomain.BaseDirectory;
            var folder = Path.Combine(parentFolder, DateTime.Now.ToString("dd-MM-yyyy"));
            if (!System.IO.Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }
            fileName = string.Format("{0}\\{1}", folder, fileName);
            screenShot.SaveAsFile(fileName, ImageFormat.Png);
        }
    }

How to Run Dynamic Test Cases

If you are familiar with Selenium, you should have already used Selenium IDE. If not, all you need to do is, download and install selenium IDE for FireFox. Once you the IDE installed, open the website you want to test and enable Selenium Web IDE and then start execution of UI test case. This will record the execution, once this is recorded. it can be exported as C# NUnit code using Selenium UI. This code is stored in database and executed dynamically later, n number of times as and when required. Thus automating Functional UI testing.

    public class DynamicCodeExecution
    {
        public static List<Results> AutoExecuteCode()
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeCompiler compiler = provider.CreateCompiler();
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;
            parameters.IncludeDebugInformation = false;
            parameters.TreatWarningsAsErrors = false;
            parameters.CompilerOptions = string.Format("/lib:{0}", "c:\\Selenium\bin");
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Core.dll");
            parameters.ReferencedAssemblies.Add("WebDriver.dll");
            parameters.ReferencedAssemblies.Add("SeleniumExtension.dll");
            string dynamicCode = new SeleniumExtension.Services.MockSqlServices().GetDynamicDataObjects().FirstOrDefault().DynamicCode; //call db and get the code
            parameters.GenerateInMemory = false;
            CompilerResults compiled = provider.CompileAssemblyFromSource(parameters, dynamicCode);
            if (compiled.Errors.HasErrors)
            {
                string errorMessage = "Has an Error : \n";

                for (int i = 0; i < compiled.Errors.Count; i++)
                {
                    errorMessage = errorMessage + "\r\nLine : " + compiled.Errors[i].Line.ToString() + " - " + compiled.Errors[i].ErrorText;
                }
                throw (new Exception(errorMessage));
            }

            Assembly assembly = compiled.CompiledAssembly;
            object instanceObject = assembly.CreateInstance("SeleniumExtension.Services.MockDynaObject");
            if (instanceObject == null)
            {
                throw (new Exception("Could not create an instance of dynamic object or the object was null"));
            }

            object[] codeParams = new object[0];

            try
            {
                object objResults = instanceObject.GetType().InvokeMember("Run", BindingFlags.InvokeMethod, null, assembly, codeParams);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            if (instanceObject != null)
                return (List<Results>)instanceObject;
            return null;
        }
    }

Source code for download

Download the source code selenium test case automation from here. The implementation require you to place Internet Explorer local host driver in the application execution path (bin) folder. Also make sure that you update the code to point to actual bin – this is required to execute the dynamic assembly.

Codeplex: https://seleniumautomation.codeplex.com/

Advertisements

Nuget – How to!

There is this fascinating packaging and distributing technology called Nuget. You can basically distribute anything, through packages that can be downloaded directly to your development environment. When I say package, I mean library files, scripts, configurations, view files etc., put together in a distributable way.

At a glimpse: I created a new MVC web application and I want to reuse a certain third library available on the internet for datagrid, how do I do it? – Simple, find out a suitable package from nuget.org, download it using Visual Studio Package Manager, Your application will now have all files, scripts, and library(dlls) that’s required to use a datagrid (along with documentation, if available as a part of package).

Intro

As I said earlier, its a packaging and distribution mechanism. Below are certain points that will help you get started.

  • You are creating a web application and would like to distribute web controls you create for re-use
  • Normally, you would package all dll’s put the dependent files in folder and zip it to a location from where people could download your package and copy-paste re-use.
  • On the other hand, lets say you have a nuget driven approach, the entire process is simplified and streamlined.
  • For packaging your web control, you will build the solution using MSBuild scripts, generate output for deployment
  • Create a nuget manifest, which will have information about the component being distributed and its version information.
  • Once you have the manifest and the Build Output, run “Nuget.exe” to get the package created.
  • Host the package at any location, FTP or Web Server.

I am going to explain every step described above, as different topics below.

Why would you package?

Before that, Nuget – this is completely based on what your organisation needs, there are good and bad to it, based on what is required. For example, you don’t have to package an application if it’s not a re-distributable component, or if it cannot accept packages from nuget gallery, for whatever reason that may be. On the other hand, package anything that’s re-usable, Project Template, Custom Controls, Styles, Scripts and so on.

What to Package?

This is the most important question that you requires a lot of analysis. When I say analysis, below are certain stuffs that you need be prepared for, when you decide on what to package.

  1. Target Framework: This is the most crucial item, you need to know which .NET framework your component is targeted for. If your component is not targeted for any particular framework, well and good, your job is less complicated. If your component targets multiple framework, there has to be clear demarcation between different dependencies for each framework.

How To Package?

There are different ways to package using Nuget and they are

  1. Assembly package : A package can be created straight from an assembly based off its manifest.
  2. Project package : You can create a package from .csproj using “Nuget.exe” compiler
  3. Folder based package : Folder based conventional packaging is most flexible and allows multiple framework for packaging.

I’m not going through the details, as they are extensively available at Nuget.org Documentation.

What do I need to Setup Nuget?

Well, you dont need anything special. All you need to do is, go to Nuget.org/Documentation and download “Nuget.exe” – Thats it, you are all set to create your own package.
Now the question is how do we distribute this package. Well thats easier than creating a package. All you need to do is Sign-Up at Nuget.org and upload you package there, after which its available for anyone. That said, you cannot upload enterprise packages onto nuget gallery thats hosted for public. So, there are two different options

  • Host nuget at a FTP location and use the FTP path as feed location in Visual studio package manager
  • Host Nuget Gallery in local environment and provide the Website URL as feed location – Nuget gallery project is open source and anyone can download and host the project at enterprise level, if required with customization.

Host Nuget in local environment using “Nuget Gallery”

Difficulties I faced while hosting this project was with SQL Server configurations, you need to create a proper connection string and update the Web.config to point to an EMPTY DATABASE. When you run the application for the first time, the Nuget Manifest database will be created automatically. The site will also require you to create a FTP location to host nuget packages – basically they will be downloaded or uploaded via application to a FTP location.

  • NUSPEC – .nuspec file is the one which contains manifest details. While you are building the package using .csproj file, this .nuspec file has to be place at the same location as project file.
  • NUPKG – .nupkg is the output nuget package file, this file can be uploaded a nuget gallery hosted locally or onto server at Nuget.org.

MVC Web Profiling – Extension

Profiling is a simple concept that allows to track visitors on website and personalize the site based on the information available at your disposal. Profiling in .NET is so simple that, all you need to do is run a Command on Visual Studio Command Prompt and then write some 10 lines of configuration and code to enable profiling. Visual Studio SDK/.NET has the ability to create the database(tables) and all other infrastructure required for profiling. To get basic profiling enabled on your application all you would need is SQL Server

The default profile implementation is most intuitive and perfect way to handle profiling for your application. However, there may be scenarios where we will have to find alternates to implementation done in profiling. We can extend the ASP.NET profiling to use a custom provider, while we are allowed to reuse most of the core profile functionalities. Here I’ll walk you through basics of setting up an Profiling infrastructure and then details on customizing profile provider.

Steps to setup Basic Profiling

  1. To begin with, I assume that, you already have created a MVC3/MVC4 Web Project
  2. Add reference to System.Web.Profile. This is MS namespace for profiling.
  3. Create a strongly typed class – this class will have all properties that you wish to profile/save in profiling database
      • We will create a sample class and mark it as serializable.
      • This class will be serialized into an XML and stored in database.
        [Serializable]
        public class User
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Timezone { get; set; }
        }
    
  4. Implement an extension to get/set values from default profile provider
        public class UserProfile : ProfileBase
        {
            public User User
            {
                get { return (User)GetPropertyValue("User"); }
            }
    
            // Gets the profile of a specific user.
            public static UserProfile GetProfile(string userName)
            {
                return (UserProfile)Create(userName);
            }
    
            //Get Profile of current user
            public static UserProfile GetProfile()
            {
                return (UserProfile)HttpContext.Current.Profile;
            }
        }
  5. Create database – Execute following command and .NET automatically creates the database
    C:\Microsot Visual Studio 11.0>aspnet_regsql -A p -S SQLSERVER08 -E
    
  6. Add configurations to enable profiling
     <connectionStrings>
        <add name="sqldatabaseprovider" connectionString="Data Source=MACHINE\SQLSERVER08;Initial Catalog=aspnetdb;Integrated Security=True;" />
      </connectionStrings>
        <anonymousIdentification enabled="true" />
        <profile defaultProvider="ProfileProvider" inherits="ProfilingExtension.Profile.UserProfile">
          <providers>
            <add name="ProfileProvider"
            type="System.Web.Profile.SqlProfileProvider"
            applicationName="myApp"
            connectionStringName="sqldatabaseprovider"/>
          </providers>
        </profile>
     
  7. How to use profile in your code:
            [HttpPost]
            public ActionResult Index(string username)
            {
                //Create an instance of Profile Object
                UserProfile profile = new UserProfile();
    
                //Access custom property
                profile.User.FirstName = username;
                profile.User.Timezone = TimeZone.CurrentTimeZone.StandardName;
    
                //Save profile for current user
                profile.Save();
                return View();
            }
    

Things to Remember:

Profiling can be done for both authorized user and anonymous user. Basically, when profiling for an authorized user, profiling uses the current context to obtain the current user ID, which can be set using ASP.NET forms/Or any authentication mechanism. For anonymous users, profiling is not supported by default, it has to be explicitly enabled. When anonymous identification is enabled profiling creates a unique ID for a user and stores it in a cookie on user machine, which is periodically cleared. This unique ID is used by profiler to identify the anonymous user, every time he or she visits the website, and personalization can be done based on this.

Steps to Extend Profiler

  1. Create a database instance – good to have have most of the schemas as defined by default profile implementation
  2. Implement the Extension for ProfileProvider – MSDN article
  3. Implement the ProfileBase extension – Will provide access to custom profile properties along with default attributes.
  4. Modify the configuration – explicitly mention if the anonymous profiling is enabled and also configure the custom properties added – MSDN Article

We are done !!

Web Optimization

Microsoft.NET Web Optimization has a bundle of features which allows it to be the most easy to customize optimization framework available yet. When I say web optimization, I’m talking about bundling, compressing and caching the assets like JavaScript(s), style sheets(less/css). The basic implementation of optimization allows you to add a specific asset to bundle through code, every time asset list or the bundling order changes you have to modify the code to update the bundles on your page. To content manage bundling, we will take an XML based approach to this problem.

Primarily, there are 3 steps involved in web optimization,

  • Add Assets to Bundle
  • Process (compress/compile/order) assets using Parsers (Less compiler, JssMinifier, CssMinifer etc..)
  • Use Html helpers to print the cached asset path on the page

We will start by creating a Standard MVC Project. If you are using visual studio 2012, All the infrastructure required to start bundling is added by default in MVC project template. For other, using VS 2010 or earlier, you will need to Install .net framework 4.5. Most important aspect is that, System.Web.Optimization.dll is the assembly that is required to enable optimization for your project. Make sure that your are not using beta version of this assembly. Here, in this example we will taking a project template created out of VS 2010 and a machine having .Net framework 4.5 installed.

Download Source Code here

Activation of Optimization Framework

We will create an Http Module that will be invoked on PostMapRequestHandler. We are creating a module in this event because, optimization module requires Session and Current HttpContext to be populated, this is the application event that can have both. On Post Map Request State, we will initiate optimization framework by creating an Instance of our custom implementation, rather than calling the system libraries directly.

Custom Wrapper for Optimization

Our custom wrapper is the one which will actually enable us to use custom XML configuration to content manage the optimization framework. Features that we will try to enable are

  • Assets to add in JavaScript bundle – Folder based / File based.
  • Assets to add in Css/Less bundle – Folder based / FIle based.
  • Asset output path – Friendly links for assets.
  • Enable / disable optimization framework completely.

System.Web.Optimization: Supports custom pipelines

Custom compilers and processors, there are two Interfaces that can be extended for using custom processing.

IBundleTransform

Implement this interface to enable custom transformation for bundles. Let us say you want to compile a specific type of asset file not directly supported by optimization framework, you can use this interface to write your own custom transformer or plugin a third-party compiler that can compile the given asset. Let us consider that we want to compile Less files to generate css styles, to have Optimization do this we can use a third-party less compiler like dotLess.

IBundleOrder

Implement this interface to enable custom sorting of files while bundling. In general while bundling JavaScript files, you wight want to include the JQuery Framework files first and then include your library files after that in a given order so that none of the references are impacted. To enable this custom sorting you can extend this interface, In our example we will extend this interface to enable file based sorting of asset files. We will place a “bundle.txt” inside a folder and the IBundleOrder implementation will look for this file and order the assets based on the file order mentioned in the file.

MVC Helpers : Helpers to Use Bundles on a Page

We will take a master and child layout based approach to asset bundles. This will help us have multiple bundles added to framework and yet use only the required ones on a page, based on the layout used by current page. Apparently this will help us save on page load time. Normally adding all assets to framework and then using the current bundle list will output even the assets thats not required on a given page. The technical approach here will require us to add assets from sub-layouts to current http context and then output them on the master layout. This approach will help us have multiple sub-layouts, which controls assets required for a set of pages, and still have a master which can control the page layout.

Possible Enhancements

It is quite possible that you can inject compilers, orderers and minifiers at runtime, this wil further make the optimization framework generic and flexible to any kind of assets or change in any SEO approaches.

Forms Authentication Basics

Introduction

Authentication is the process of determining whether someone or something is, in fact, who or what it is declared to be. In General authentication is done using Logon methods. We are going to have a look at general authentication mechanism used in web application, Forms authentication. This is one of the most commonly used form of authentication for web applications.

Topics

  • Basics of Form Authentication
  • Design
  • Custom Authentication
  • Authenticate Request
  • Authorize Action Filter

Basics of Form Authentication

To enable forms authentication make sure that, application has proper configurations enabled.

  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Index" timeout="2880" />
    </authentication>
  </system.web>

Identity

Basic forms authentication discussed here authorizes user on whose behalf the code is running. Read more about IIdentity here.

Forms Authentication Ticket

This ticket is used to store data required to authenticate user. Read more here.

Form Authentication

FormsAuthentication is used as service to manage all web authentication request. Read more here

Design

  • ICustomAuthentication Interface will authenticate user and create custom authentication principal.
  •  public interface ICustomAuthentication
     {
         void Authenticate(string username, string password);
         void CreateCustomPrincipal();
     }
    
  • IDataService Interface will take care of interacting with database to validate the current user information with details stored in the system/database.
  •  public interface IDataService
     {
        bool CheckCredentials(string username, string password)
     }
    

Custom Authentication

Below is a sample implementation of custom authentication interface described above.

Authenticate

This method takes username and password as input and checks for the validity of credentials. If its valid, a forms authentication cookie is created and encrypted and assigned to HttpContext.

CreateCustomPrincipal

Once the user is authenticated and the authentication cookie is created, current User is set to a generic/custom Prinicpal created out of IIdentity Interface.

public class SecurityServices : Interfaces.Security.ICustomAuthentication
{
        public void Authenticate(string username, string password)
        {
            DataServices ds = new DataServices();

            if (!ds.CheckCredentials(username, password))
                return;

            var authTicket = new FormsAuthenticationTicket(1, username, DateTime.Now,
                                               DateTime.Now.AddSeconds(30), true, "");

            string cookieContents = FormsAuthentication.Encrypt(authTicket);

            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieContents)
            {
                Expires = authTicket.Expiration,
                Path = FormsAuthentication.FormsCookiePath
            };

            if (HttpContext.Current != null)
            {
                HttpContext.Current.Response.Cookies.Add(cookie);
            }

            return;
        }

        public void CreateCustomPrincipal()
        {
            HttpCookie authCookie =   HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie != null)
            {
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                var identity = new GenericIdentity(authTicket.Name, "Forms");
                var principal = new CustomPrincipal(identity);
                HttpContext.Current.User = principal;
            }
         }
 }

CustomPrincipal

Custom principal will contain the role validation and the authentication status for the current user, this is an extension of IPrincipal.

public class CustomPrincipal : IPrincipal
{
        public CustomPrincipal(IIdentity identity)
        {
            Identity = identity;
        }

        public bool IsInRole(string role)
        {
            if (String.Compare(role, "admin", true) == 0)
            {
                return (Identity.Name == "admin");
            }
            else
            {
                return false;
            }
        }

        public IIdentity Identity
        {
            get;
            private set;
        }
}

Authenticate Request

In this example, Http pipeline is used to authenticate the request. To add a new http module to the current pipeline, add below configuration. Make sure that Type and dll is updated properly.

<system.web>
  <httpModules>
     <add name="SecurityAuthModule" 
          type="WebSecurity.Pipeline.HttpSecurityPipeline, WebSecurity"/>
  </httpModules>
</system.web>

Authorize request will be invoked by Http module on AuthenticateRequest as shown below.

public class HttpSecurityPipeline : IHttpModule
{
        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public void Init(HttpApplication context)
        {
            context.AuthenticateRequest += new EventHandler(this.ApplicationAuthRequest);
        }

        protected void ApplicationAuthRequest(object sender, EventArgs args)
        {
            new WebSecurity.SecurityServices().CreateCustomPrincipal();
        }
}

Authorize Request

When you mark an action method with AuthorizeAttribute, access to that action method is restricted to users who are both authenticated and authorized. If you mark a controller with the attribute, all action methods in the controller are restricted. Read more here.

[Authorize]
public class HomeController : Controller
{
        //
        // GET: /Home/
        public ActionResult Index()
        {
            ViewData.Add(new KeyValuePair<string, object>("User", User.Identity.Name));
            return View();
        }
}

How to Use Simple Authentication

    public class AccountController : Controller
    {
        //
        // GET: /Account/
        [AllowAnonymous]
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Login()
        {
            new WebSecurity.SecurityServices().Authenticate("UserName", "password");
            return RedirectToAction("Index", "Home");
        }
    }

Download Project Source code