NashTech Blog

Scalable Selenium Framework in C# with NUnit

Table of Contents

Introduction

Test automation plays a crucial role in modern software development by ensuring faster delivery and consistent quality. By automating repetitive tests, teams can catch defects early, reduce manual testing time, and focus more on development. However, a successful automation framework requires careful planning and best practices. This blog explores how to build a Scalable Framework in C# with NUnit and Selenium, focusing on performance, maintainability, and ease of integration with CI/CD pipelines.

In this blog, we will dive into how to build a scalable test automation framework using C#, Selenium, and NUnit. We will explore why these tools are popular choices, discuss the advantages and disadvantages of a scalable test automation framework, and provide a working example of a login test case.

Why Choose C#, Selenium, and NUnit?

  • C#: It is a powerful object-oriented programming language, commonly used for enterprise-level applications, and integrates well with Selenium. C# offers rich libraries, clear syntax, and robust debugging tools, making it a top choice for many automation testers.
  • Selenium: Selenium WebDriver is an open-source tool for automating web browsers. It allows testers to simulate real user interactions, making it ideal for functional and regression testing. It supports multiple programming languages, including C#, and works across different browsers.
  • NUnit: NUnit is a popular testing framework for C# applications. It provides features like assertions, test case setup/teardown, and parallel test execution. Its integration with tools like ExtentReports and CI/CD pipelines helps in creating efficient, maintainable, and scalable test automation solutions.

Why Build a Scalable Test Automation Framework?

As applications grow in complexity, maintaining individual test scripts becomes challenging. A scalable test automation framework provides a structured approach that:

  • Simplifies Test Maintenance: With modular design and reusable components, tests are easier to update and manage.
  • Improves Reusability: Common actions and web elements are centralized, making it faster to write new tests.
  • Supports Parallel Execution: Scalable frameworks can execute tests in parallel, saving time and resources.
  • Eases Integration with CI/CD: A well-designed framework integrates seamlessly with Continuous Integration (CI) and Continuous Delivery (CD) pipelines, ensuring faster feedback loops.

Advantages

  • Modular Design: Reusable components for faster test development.
  • Easy Maintenance: Allows for easy updates when the application’s UI or functionality changes.
  • Parallel Execution: Running tests in parallel drastically reduces execution time.
  • Extensive Reporting: Provides detailed reports with screenshots and logs, offering better visibility into test results.
  • Continuous Integration Friendly: Easily integrates with CI/CD tools like Jenkins, Azure DevOps, etc.

Disadvantages

  • High Setup Effort Initially: Requires significant upfront planning and setup.
  • Learning Curve: Developers and testers must invest time in understanding Selenium, NUnit, and C# programming practices.
  • Ongoing Maintenance: Frequent UI changes can break tests, requiring constant updates.
  • False Failures (Flakiness): Dynamic elements, slow loading, and improper wait handling can lead to flaky tests.

Framework Structure Overview

Here’s the basic structure of the test automation framework:

TestAutomation/
├── Base/
│   └── BaseTest.cs
├── Drivers/
│   └── WebDriverSetup.cs
├── Pages/
│   └── TestLoginPage.cs
├── Reports/
│   └── ExtentReportManager.cs
├── TestData/
│   └── LoginTestData.csv
├── Tests/
│   └── PracticeTestAutomation.cs
├── Utilities/
│   ├── WaitHelper.cs
│   └── TestDataReader.cs
├── ExtentReport.html

Framework Core Components Explained

  • BaseTest.cs: Contains setup and teardown logic, such as initializing and quitting the WebDriver.
  • WebDriverSetup.cs: Responsible for creating and initializing the WebDriver, such as ChromeDriver or FirefoxDriver.
  • TestLoginPage.cs: Page Object Model class that abstracts the actions on the login page (like entering credentials and clicking the login button).
  • ExtentReportManager.cs: Manages the ExtentReports to generate detailed test execution reports.
  • PracticeTestAutomation.cs: The actual test class containing test cases that use the Page Object Model methods to perform actions on the application.

Working Example

Let’s walk through a simple login test case example. This test case will verify that the login functionality works as expected by checking the success message after logging in.

We will also include report generation using ExtentReports.

Code Breakdown

BaseTest.cs
using NUnit.Framework;
using OpenQA.Selenium;
using TestAutomation.Drivers;
using AventStack.ExtentReports;

namespace TestAutomation.Base
{
    public class BaseTest
    {
        protected IWebDriver driver;
        protected ExtentReports extent;
        protected ExtentTest test;

        [OneTimeSetUp]
        public void Setup()
        {
            // Initialize WebDriver and ExtentReports
            WebDriverSetup setup = new WebDriverSetup();
            driver = setup.InitializeDriver();

            extent = ExtentReportManager.GetExtentReports();
        }

        [TearDown]
        public void TearDown()
        {
            // Close the WebDriver
            if (driver != null)
            {
                driver.Quit();
            }

            // Flush ExtentReports
            extent.Flush();
        }
    }
}
WebDriverSetup.cs
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace TestAutomation.Drivers
{
    public class WebDriverSetup
    {
        public IWebDriver InitializeDriver()
        {
            // Set ChromeDriver path
            var driverService = ChromeDriverService.CreateDefaultService();
            var options = new ChromeOptions();

            // Configure ChromeOptions if necessary
            options.AddArgument("--headless");

            IWebDriver driver = new ChromeDriver(driverService, options);
            driver.Manage().Window.Maximize();
            driver.Navigate().GoToUrl("https://www.example.com");

            return driver;
        }
    }
}
TestLoginPage.cs
using OpenQA.Selenium;

namespace TestAutomation.Pages
{
    public class TestLoginPage
    {
        private readonly IWebDriver _driver;

        // Locators
        private readonly By _loginButton = By.Id("loginButton");
        private readonly By _usernameField = By.Id("username");
        private readonly By _passwordField = By.Id("password");
        private readonly By _successMessage = By.Id("successMessage");

        public TestLoginPage(IWebDriver driver)
        {
            _driver = driver;
        }

        public void NavigateToLoginPage()
        {
            _driver.Navigate().GoToUrl("https://www.example.com/login");
        }

        public void PerformLogin(string username, string password)
        {
            _driver.FindElement(_usernameField).SendKeys(username);
            _driver.FindElement(_passwordField).SendKeys(password);
            _driver.FindElement(_loginButton).Click();
        }

        public string GetSuccessMessage()
        {
            return _driver.FindElement(_successMessage).Text;
        }
    }
}
ExtentReportManager.cs
using AventStack.ExtentReports;
using AventStack.ExtentReports.Reporter;

namespace TestAutomation.Reports
{
    public class ExtentReportManager
    {
        private static ExtentReports extent;

        public static ExtentReports GetExtentReports()
        {
            if (extent == null)
            {
                string reportPath = "ExtentReport.html";
                var sparkReporter = new ExtentSparkReporter(reportPath);
                extent = new ExtentReports();
                extent.AttachReporter(sparkReporter);
            }

            return extent;
        }
    }
}
LoginTests.cs
using NUnit.Framework;
using TestAutomation.Base;
using TestAutomation.Pages;
using TestAutomation.Reports;
using AventStack.ExtentReports;

namespace TestAutomation.Tests
{
    public class LoginTests : BaseTest
    {
        private TestLoginPage loginPage;
        private ExtentReports extent;
        private ExtentTest test;

        [OneTimeSetUp]
        public void ReportingSetup()
        {
            extent = ExtentReportManager.GetExtentReports();
        }

        [Test, Order(1)]
        public void LoginTest_Passing()
        {
            test = extent.CreateTest("Login Test - Passing");

            loginPage = new TestLoginPage(driver);
            loginPage.NavigateToLoginPage();
            loginPage.PerformLogin("student", "Password123");

            Assert.That(loginPage.GetSuccessMessage(), Is.EqualTo("Logged In Successfully"), "Login success message mismatch.");

            test.Pass("Login successful and title verified.");
        }

        [Test, Order(2)]
        public void LoginTest_Failing()
        {
            test = extent.CreateTest("Login Test - Failing Assertion");

            loginPage = new TestLoginPage(driver);
            loginPage.NavigateToLoginPage();
            loginPage.PerformLogin("student", "Password123");

            Assert.That(loginPage.GetSuccessMessage(), Is.EqualTo("Wrong Title"), "Login success message mismatch."); // Intentional fail

            test.Pass("This should fail as title mismatch.");
        }

        [OneTimeTearDown]
        public void TearDownReporting()
        {
            extent.Flush();
        }
    }
}

Conclusion

Building a scalable and maintainable test automation framework is crucial for long-term success in software testing. By following best practices such as modular design, parallel execution, and detailed reporting, you can ensure your framework remains easy to scale and maintain.

With the integration of Selenium, NUnit, and C#, the framework can be used for various types of applications, providing high-quality automated tests.

Picture of PrajaktaSatpute

PrajaktaSatpute

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top