Deep Dive : Automated software testing with Visual Studio

By | November 14, 2015

In present day, each one of us wants to use tools which can help us reduce our day to day work without compromising the accuracy and so we look forward to automate our software’s too.

Let’s first understand what automation testing is. I love the definition stated in the book ‘Fuzzy Expert Systems for Disease Diagnosis’ which goes as:

Automated software testing is a process in which software tools execute pre-scripted tests on a software application before it is released into production.

Why automate Testing?

In practice, what we see is that testing is not given as much emphasis as development in order to save time and money but most of the time it backfires with issues like poor quality and dissatisfied end users This makes it necessary to revisit the software hence impacting the factors such as time and money which were initially the reason for neglecting it.

The reasons which make automation of test cases so important are:

  • Saves time and money

Automation of test cases can run fast and frequently.

  • Testing improves accuracy

Automation of test cases leaves you to accurate result.

  • Increase team morale

Automation of test cases helps testers get rid of the boring task of executing the same set of test cases repeatedly and give them time that can be spent on creating more new and effective test cases.

  • Automation helps developers

Automation of test cases helps developers to figure out errors/problems even before sending it to the test team. Whenever source code changes, they are checked in else it notifies the team or the developer if they fail.

The automation of tests is initially associated with increased effort, but the related benefits will quickly pay off.

When to create an automation test?

We should always keep in mind that if quality assurance (QA) team is performing any task repeatedly, then it’s an ideal candidate for automation testing. The major objective of automated testing is to simplify as much of the testing effort as possible with a minimum set of scripts.

The beauty of automated testing is that it not only helps with the execution of a set of unit test cases, but it can be run repeatedly at any time and are also capable of generating reports.

Creating Automated Tests

We can create several types of automated tests which enable us to test our application more efficiently. Automated tests run the test steps for us and determines whether the test passes or fails. These tests can be run more quickly and more frequently. Automated tests can quickly test whether the application is still working correctly after code changes have been made to the application. Automated tests can be created using Visual Studio.

 

Here, we will learn how to automate website testing using Selenium. So the first question which comes to our mind is Selenium?

Yes, you got it right! It is the chemical element with the atomic number 34. Actually Selenium was an internal tool at ThoughtWorks originally developed by Jason Huggins in 2004. The name Selenium comes from a joke made by Huggins in an email mocking a competitor named Mercury, saying that we can cure mercury poisoning by taking selenium supplements. In short Selenium is test automation framework for web applications.

In our article we will learn some basic steps of web automation testing and will keep learning more about it in subsequent articles. So let’s get our hand dirty :)

Step1: Open visual studio and create a new MVC application

1

2

 

Step2: Add a class library called WebAutomationApplication.TestFrameWork. As the name suggests it’s going to be our test framework.

3

4

 

Step 3: Add selenium dll through selenium nuget package to our test framework.

5

6

 

Step 4: Add a class called Driver under a folder named Selenium.

public class Driver
{
    public static IWebDriver Instance;
    public static string BaseAddress
    {
        get
        {
            return "http://localhost:39430/";
        }
    }

    public static void Initialize()
    {
        Instance = new FirefoxDriver();
    }

    public static void Close()
    {
        Instance.Close();
    }
}

 

The Driver class has the following methods and properties:

  • Initialize- which is responsible for creating an instance of Firefox browser.
  • Close – which is responsible for closing the instance of Firefox browser.
  • BaseAddress – which has the base url of your site. (Please configure it accordingly and if possible read it from a config file.)

 

Step 5: Add a unit test project called WebAutomationApplication.Test and add reference to WebAutomationApplication.TestFrameWork

7

8

 

Step6: Now let’s try testing register page. In order to do that, lets run the web application first and go to register page.

9

Here we can figure out that in order to test this page, we need to validate 3 fields:

  • Email
  • Password
  • Confirm Password

So let’s get started with all different scenarios

 

Scenario1: User submits an empty page.

When a user submits an empty page, then he/she should get an error messages for the same.

Add a RegisterPageTest.cs file to WebAutomationApplication.Test

[TestClass]
public class RegisterPageTest
{
    [TestInitialize]
    public void Init()
    {
        Driver.Initialize();
    }

    [TestCleanup]
    public void Cleanup()
    {
        Driver.Close();
    }
}

We need to add attribute [TestClass] to make a class unit testable. The attribute [TestInitialize] is mentioned above those methods which need to be executed before all test cases while [TestCleanup] is mention above those methods which need to be executed after all the test cases.

Now we need to create a test case which will test empty submission of the register page. In order to do that, we first need to navigate to the register page and then click on the submit button.

[TestMethod]
public void User_Submit_Empty()
{
    RegisterPage.Goto();

    RegisterPage.WithEmailId(string.Empty)
        .WithPassword(string.Empty)
        .WithConfirmPassword(string.Empty)
        .Register();

    CollectionAssert.Contains(RegisterPage.Errors, "The Email field is required.");
    CollectionAssert.Contains(RegisterPage.Errors, "The Password field is required.");
}

Next we see that we have tried to call methods as per statement i.e. Go to register page, then sign up with empty email id and password and then click on the register button and then assert if we see the corresponding error messages. But we do see that the class register page is missing so now let’s create that.

Add a file called RegisterPage.cs to folder called Page under WebAutomationApplication.Test project and now add a Goto method to it. This method will help navigating to register page.

public static void Goto()
{
    Driver.Instance.Navigate().GoToUrl(Driver.BaseAddress + "Account/Register");
}

In the next step we will add a method called WithEmailId which is responsible to fill the email id with the required field and return a RegisterCommand.

public static RegisterCommand WithEmailId(string emailId)
{
    return new RegisterCommand(emailId);
}

Now we add a class called RegisterCommand.cs in Command folder under Pages folder.

public class RegisterCommand
{
    private string emailId;
    private string password;
    private string confirmPassword;
        
    public RegisterCommand(string emailId)
    {
        this.emailId = emailId;
    }

    public RegisterCommand WithPassword(string password)
    {
        this.password = password;
        return this;
    }

    public RegisterCommand WithConfirmPassword(string confirmPassword)
    {
        this.confirmPassword = confirmPassword;
        return this;
    }

    public void Register()
    {
        IWebElement emailInput = Driver.Instance.FindElement(By.Id("Email"));
        emailInput.SendKeys(emailId);

        IWebElement passwordInput = Driver.Instance.FindElement(By.Id("Password"));
        passwordInput.SendKeys(password);

        IWebElement confirmPasswordInput = Driver.Instance.FindElement(By.Id("ConfirmPassword"));
        confirmPasswordInput.SendKeys(confirmPassword);

        IWebElement signupButton = Driver.Instance.FindElement(By.ClassName("btn"));
        signupButton.Click();
    }
}

In this we first assign all the values provided by the user to their corresponding fields and then in register method we will find the necessary controls either by their id or class using Selenium and assign them to their corresponding fields and then find register button and click on that.

The last thing which is left in this scenario is to validate whether error messages are shown or not. To do so, we will create a list which contains all the error messages in RegisterPageTest class which is asserted by CollectionAssert in User_Submit_Empty_Register_Page method.

private static List<string> errors;
public static List<string> Errors
{
    get
    {
        errors = new List<string>();
        var ul = Driver.Instance.FindElement(By.CssSelector("div.validation-summary-errors ul"));

        var lis = ul.FindElements(By.TagName("li"));
        foreach (var li in lis)
        {
            errors.Add(li.Text);
        }
        return errors;
    }
}

At last our three class files should look like this:

[TestClass]
public class RegisterPageTest
{
    [TestInitialize]
    public void Init()
    {
        Driver.Initialize();
    }

    [TestCleanup]
    public void Cleanup()
    {
        Driver.Close();
    }

    [TestMethod]
    public void User_Submit_Empty()
    {
        RegisterPage.Goto();

        RegisterPage.WithEmailId(string.Empty)
            .WithPassword(string.Empty)
            .WithConfirmPassword(string.Empty)
            .Register();

        CollectionAssert.Contains(RegisterPage.Errors, "The Email field is required.");
        CollectionAssert.Contains(RegisterPage.Errors, "The Password field is required.");
    }
}

public class RegisterPage
{
    private static List<string> errors;
    public static List<string> Errors
    {
        get
        {
            errors = new List<string>();
            var ul = Driver.Instance.FindElement(By.CssSelector("div.validation-summary-errors ul"));

            var lis = ul.FindElements(By.TagName("li"));
            foreach (var li in lis)
            {
                errors.Add(li.Text);
            }
            return errors;
        }
    }

    public static void Goto()
    {
        Driver.Instance.Navigate().GoToUrl(Driver.BaseAddress + "Account/Register");
    }

    public static RegisterCommand WithEmailId(string emailId)
    {
        return new RegisterCommand(emailId);
    }
}

public class RegisterCommand
{
    private string emailId;
    private string password;
    private string confirmPassword;
        
    public RegisterCommand(string emailId)
    {
        this.emailId = emailId;
    }

    public RegisterCommand WithPassword(string password)
    {
        this.password = password;
        return this;
    }

    public RegisterCommand WithConfirmPassword(string confirmPassword)
    {
        this.confirmPassword = confirmPassword;
        return this;
    }

    public void Register()
    {
        IWebElement emailInput = Driver.Instance.FindElement(By.Id("Email"));
        emailInput.SendKeys(emailId);

        IWebElement passwordInput = Driver.Instance.FindElement(By.Id("Password"));
        passwordInput.SendKeys(password);

        IWebElement confirmPasswordInput = Driver.Instance.FindElement(By.Id("ConfirmPassword"));
        confirmPasswordInput.SendKeys(confirmPassword);

        IWebElement signupButton = Driver.Instance.FindElement(By.ClassName("btn"));
        signupButton.Click();
    }
}

Finally we have reached our last step. Select WebAutomationApplication project as the start project and run the application. Post that we go to test menu item, select run and all test. Wait for some time to see if all test passes in the test explorer.

 

10

11

 

Scenario 2: User submits an invalid email id.

[TestMethod]
public void User_Submit_Incorrect_EmailId()
{
    RegisterPage.Goto();

    RegisterPage.WithEmailId("shashank")
        .WithPassword("password")
        .WithConfirmPassword("password")
        .Register();

    CollectionAssert.Contains(RegisterPage.Errors, "The Email field is not a valid e-mail address.");
}

 

Scenario 3: User submits different password and confirm password.

[TestMethod]
public void User_Submit_Different_Password_And_ConfirmPassword()
{
    RegisterPage.Goto();

    RegisterPage.WithEmailId("test@gmail.com")
        .WithPassword("password")
        .WithConfirmPassword("password1")
        .Register();

    CollectionAssert.Contains(RegisterPage.Errors, "The password and confirmation password do not match.");
}

 

Scenario 4: User submits a password which is less than 6 characters long.

[TestMethod]
public void User_Submit_Small_Password()
{
    RegisterPage.Goto();

    RegisterPage.WithEmailId("test@gmail.com")
        .WithPassword("key")
        .WithConfirmPassword("key")
        .Register();

    CollectionAssert.Contains(RegisterPage.Errors, "The Password must be at least 6 characters long.");
}

 

Scenario 5: User submits an invalid password.

[TestMethod]
public void User_Submit_Invalid_Password()
{
    RegisterPage.Goto();

    RegisterPage.WithEmailId("test@gmail.com")
        .WithPassword("password")
        .WithConfirmPassword("password")
        .Register();

    CollectionAssert.Contains(RegisterPage.Errors, "Passwords must have at least one non letter or digit character. Passwords must have at least one digit ('0'-'9'). Passwords must have at least one uppercase ('A'-'Z').");
}

 

Scenario 6: User submit valid data.

[TestMethod]
public void User_Submit_Valid_Data()
{
    var emailId = string.Format("test{0}@gmail.com", Guid.NewGuid());
    RegisterPage.Goto();

    RegisterPage.WithEmailId(emailId)
        .WithPassword("Password@2015")
        .WithConfirmPassword("Password@2015")
        .Register();

    Assert.AreEqual(HomePage.GreetingMessage, string.Format("Hello {0}!", emailId));
}

Once the user has provided valid credentials, he/she will be redirected to the home page and there will be a greeting on the top right saying “hello {emailId}!”. In order to achieve this, let’s create homepage.cs under Pages folder in WebAutomationApplication.TestFrameWork.

public class HomePage
{
    public static string GreetingMessage
    {
        get
        {
            var greetingMessage = string.Empty;
            var div = Driver.Instance.FindElement(By.Id("logoutForm"));

            var lis = div.FindElements(By.TagName("li"));
            if (lis != null && lis.Any())
            {
                greetingMessage = lis.First().Text;
            }
            return greetingMessage;
        }
    }
}

Hurray we are done, please try all at the test cases from test explorer and validate that they all passes :).

3 thoughts on “Deep Dive : Automated software testing with Visual Studio

  1. Pingback: Visual Studio – Developer Top Ten for Nov 30th, 2015 - Dmitry Lyalin

  2. Pingback: Top 10 Most Popular .NET Tips of the Year

  3. Pingback: Compelling Sunday – 20 Posts on Programming and QA

Comments are closed.