October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk6 min

Page Object Model in Selenium with C#: A Tutorial

A practical Selenium C# Page Object Model tutorial: organize locators and page services, compose reusable components, and keep application assertions in tests.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In Selenium with C#, the Page Object Model (POM) puts page-specific locators and actions in page or component classes, while tests keep assertions about application behavior. That division makes tests easier to read and localizes UI changes: update a locator in the page object rather than hunting for it across tests. It reduces duplication; it does not eliminate test maintenance.

What a page object should own

A page object is an object-oriented interface to a web page or a reusable part of one. It collects knowledge of the page’s HTML and locators and provides methods that express services a user or test can perform there. Selenium’s guidance describes the pattern in Java; the design principles apply in C#, but Java syntax should not be copied as if it were C#.

  • Keep inside the object: locators for the page or component and methods that perform meaningful actions.
  • Keep in the test: assertions about whether the application behaved as expected.
  • Expose intention, not mechanics: a method such as SubmitLogin is usually clearer than making every test issue low-level WebDriver commands.

Selenium’s guidance says, “Page objects themselves should never make verifications or assertions.” A narrow exception is checking that the expected page has loaded when its page object is created. That check verifies the object’s precondition; it should not replace the test’s assertion about the outcome under test. See Selenium’s Page Object Models documentation.

Set up Selenium for C#

Selenium’s getting-started instructions distinguish two .NET paths. The test-suite example lists .NET SDK 8.0 or later and uses dotnet restore and dotnet test. Its separate standalone, file-based HelloSelenium.cs path requires .NET 10 or later. The latter requirement does not apply to every Selenium C# project. Check the current instructions before choosing a setup, since SDK guidance can change: Write your first Selenium script.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The official getting-started material describes a test project; exact project structure and package references depend on the chosen test framework and current template. Selenium’s .NET API documentation lists the Selenium.WebDriver and Selenium.Support modules. Use the current API reference for signatures rather than translating Java examples by guesswork: Selenium .NET API Docs.

Rider and Visual Studio Code are among the IDE options Selenium names. An IDE can help write and execute Selenium code, but neither is a Selenium requirement. See Organizing and Executing Selenium Code.

Build a page object and keep the assertion in the test

The following is an illustrative C# pattern, not a Selenium-provided class or a verified, executed sample. It uses Selenium’s familiar IWebDriver and By concepts; confirm signatures and package details against the API version in your project. Replace the sample selectors with selectors from your application.

using OpenQA.Selenium;

public sealed class LoginPage
{
    private readonly IWebDriver driver;
    private readonly By username = By.Id("username");
    private readonly By password = By.Id("password");
    private readonly By submit = By.CssSelector("button[type='submit']");

    public LoginPage(IWebDriver driver)
    {
        this.driver = driver;
        // Optional page-object precondition: confirm the expected page is loaded.
        if (!driver.FindElement(username).Displayed)
        {
            throw new InvalidOperationException("Login page did not load.");
        }
    }

    public HomePage LoginAs(string user, string secret)
    {
        driver.FindElement(username).SendKeys(user);
        driver.FindElement(password).SendKeys(secret);
        driver.FindElement(submit).Click();
        return new HomePage(driver);
    }
}

public sealed class HomePage
{
    private readonly IWebDriver driver;
    private readonly By greeting = By.CssSelector("[data-testid='greeting']");

    public HomePage(IWebDriver driver) => this.driver = driver;

    public string GreetingText => driver.FindElement(greeting).Text;
}

The method names here—LoginAs and GreetingText—are illustrative, not Selenium-defined APIs. The test creates or receives the driver, passes it into the page object, calls the page’s service, and checks the application result:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
var login = new LoginPage(driver);
var home = login.LoginAs("test-user", "example-password");

Assert.That(home.GreetingText, Is.EqualTo("Welcome, test-user"));

The assertion framework and driver lifecycle depend on your test project. The important boundary is that the test states what success means; the page object knows how to interact with the page. Selenium recommends that public methods represent the services offered by a page or component, and that page objects seldom expose the underlying driver.

Represent an expected failed login without hiding its assertion

If a login attempt should fail, model the resulting page or state explicitly. For example, a method could submit credentials and return a login-page representation with an error-text property, or return a distinct error page object if navigation occurs. The test then asserts the expected error text. Keep the assertion out of the page object even when the object provides the method used to read that text.

Use component objects for repeated regions

A page object does not need to represent a whole page. If a navigation menu, account panel, or other region appears on several pages, give that region its own component object and compose it into each page. This keeps the component’s locator knowledge in one place without building a giant base class that obscures what each page can do.

public sealed class MainNavigation
{
    private readonly IWebDriver driver;
    private readonly By accountLink = By.CssSelector("a[href='/account']");

    public MainNavigation(IWebDriver driver) => this.driver = driver;

    public void OpenAccount() => driver.FindElement(accountLink).Click();
}

public sealed class HomePageWithNavigation
{
    public MainNavigation Navigation { get; }

    public HomePageWithNavigation(IWebDriver driver)
    {
        Navigation = new MainNavigation(driver);
    }
}

This composition is a design illustration. Choose components around coherent, repeated services rather than splitting every visual element into a class. Avoid exposing a general-purpose driver surface through every page object; tests that need unrestricted WebDriver operations can otherwise bypass the interface the model is meant to provide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a structure that keeps tests understandable

There is no single class layout that fits every application. Evaluate the design by whether it reduces duplicated locator and HTML knowledge, keeps tests readable, reuses genuinely repeated regions, and leaves assertions visible in test code.

  • If tests repeat selectors and click sequences, move that page-specific knowledge into a page object.
  • If the same coherent region appears across pages, consider a component object and compose it.
  • If a page class becomes a collection of unrelated low-level commands, narrow its public methods to meaningful page services.
  • If a base class or helper hides the behavior a test performs, prefer explicit composition or a clearer page method.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common POM problems

A locator fails after a UI change

Update the locator in the page or component that owns it, then check whether the page’s services and the affected tests still describe the current UI. POM localizes locator maintenance; it cannot prevent changes to application behavior from requiring test updates.

The page object throws while it is being constructed

First confirm that the test navigated to the expected page before creating the object. Then verify that the chosen locator matches the current page and that the element is present when the constructor checks it. Keep constructor checks narrow: they should establish that the object represents the expected page, not assert the test’s business outcome.

Tests contain many raw WebDriver calls

Move repeated, page-specific interactions behind intention-revealing methods. Do not abstract every WebDriver call automatically; a page object is useful when its methods express a service and make tests clearer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
The SQL Programming Language: .
  • Used Book in Good Condition

Assertions are buried in page methods

Return the information or page representation the test needs, then assert in the test. For a successful login, for example, return a home-page object and assert its visible result. For a failed login, expose the error state or text and assert that it matches expectations.

Java sample code does not compile in C#

The Selenium Page Object Models page illustrates the pattern in Java, not a C# implementation. Consult the .NET API reference for C# types, namespaces, and signatures, and treat translated examples as design guidance rather than compile-ready code.

Or skip the browser setup

If the task is capturing a website image or PDF rather than building an interactive browser test, ScreenshotNeo offers a one-call screenshot API and an MCP server. This does not replace Selenium POM for testing application behavior. A capture request can look like this (see the ScreenshotNeo API documentation):

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo accepts cookie or consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients. The free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a free ScreenshotNeo account to try 1,000 screenshots a month with no card.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

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

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
  2. Cupertino desk5 min
    Apple Unveils AirPods Max 2: The Upgrade That Should Have Happened Years AgoAirPods Max 2 adds H2-powered audio features and Apple claims up to 1.5Ă— more effective ANC, but its design, Smart Case, and 20-hour battery rating are unchanged. Wired lossless audio…
  3. Cupertino desk4 min
    Apple’s OLED Touch MacBooks Are Coming—but the Dynamic Island Is the Real GambleApple has not announced an OLED touchscreen MacBook, but reports point to high-end models arriving in late 2026 or early 2027. The reported Mac Dynamic Island could be useful, but…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.