Click here to Skip to main content
14,335,049 members

Atata - C# Web Test Automation Framework

Rate this:
4.87 (45 votes)
Please Sign up or sign in to vote.
4.87 (45 votes)
15 May 2019CPOL
An introduction to Atata C#/.NET web test automation full-featured framework based on Selenium WebDriver

Introduction

Atata Framework - C#/.NET web test automation full featured framework based on Selenium WebDriver.  It uses fluent page object pattern; has unique logging system; contains triggers functionality; has a set of ready to use components. Supports .NET Framework 4.0+ and .NET Core/Standard 2.0+.

The Framework basically consists of the following concepts:

  • Components (controls and page objects)
  • Attributes of the control search
  • Settings attributes
  • Triggers
  • Verification attributes and methods

Features

  • WebDriver. Based on Selenium WebDriver and preserves all its features.
  • Page Object Model. Provides unique fluent page object pattern that is easy to implement and maintain.
  • Components. Contains a rich set of ready to use components for inputs, tables, lists, etc.
  • Integration. Works on any .NET test engine (e.g. NUnit, xUnit, SpecFlow) as well as on CI systems like Jenkins, Azure DevOps or TeamCity.
  • Triggers. A bunch of triggers to bind with different events to extend component behavior.
  • Verification. A set of fluent assertion methods and triggers for the component and data verification.
  • Configurable. Defines the default component search strategies as well as additional settings. Atata.Configuration.Json provides flexible JSON configurations.
  • Reporting/Logging. Built-in customizable logging and screenshot capturing functionality.
  • Extensible. Atata.Bootstrap and Atata.KendoUI packages have a set of ready to use components. Framework supports any kind of extending.

Background

An idea of the Atata Framework is to create complex, extensible and customizable web test automation framework for any kind of websites using Selenium WebDriver and C#/.NET.

References

A list of links related to the framework:

To install it from NuGet Package Manager Console, run Install-Package Atata

Usage

I would like to show the usage of the framework using the demo website. It is a simple website that contains the following: Sign In page, Users page, User Details page and User Edit window.

The test project will use the NuGet packages: Atata, Atata.Bootstrap, Selenium.WebDriver, Selenium.WebDriver.ChromeDriver, NUnit and NUnit3TestAdapter.

I use NUnit but it is not required, you can use any .NET testing framework like MSTest or xUnit. But for me, NUnit fits the best.

Let's try to implement an auto-test for the following test case:

  1. Sign In on https://demo.atata.io/signin page.
  2. Click "New" button on User List page.
  3. Create a new user.
  4. Verify the new user's data on User List page.
  5. Navigate to the user's details.
  6. Verify the user's details.

Any page can be represented with the page object. I will try to explain the Atata's stuff step by step. To start, we need to implement the page object class for Sign In page.

Sign In Page

Sign In page

using Atata;

namespace SampleApp.UITests
{
    using _ = SignInPage;

    [Url("signin")]
    [VerifyTitle]
    [VerifyH1]
    public class SignInPage : Page<_>
    {
        public TextInput<_> Email { get; private set; }

        public PasswordInput<_> Password { get; private set; }

        public Button<UsersPage, _> SignIn { get; private set; }
    }
}
SignInPage.cs

In Atata, you operate with controls, rather than IWebElement's. The page object consists of the controls. Any control like TextInput wraps the IWebElement and has its own set of methods and properties for the interaction with it. Find out more about the components in the documentation.

Please note the 5th line of the above code:

using _ = SignInPage;

It is made to simplify the use of class type for the declaration of the controls, as every control has to know its owner page object (specify single or last generic argument). It's just a syntactic sugar and, of course, you can declare the controls this way:

public TextInput<SignInPage> Email { get; private set; }

SignIn button, as you can see, is defined with 2 generic arguments: the first one is the type of the page object to navigate to, after the button is clicked; the other one is the owner type. For the buttons and links that don't perform any navigation, just pass single generic argument, the owner page object.

It is possible to mark the properties with the attributes to specify the finding approach (e.g. FindById, FindByName). In the current case, it is not needed, as the default search for inputs is FindByLabel and for buttons is FindByContentOrValue, and it suits our needs. Find out more about the control search in the documentation.

There is also Url attribute which specifies relative (can be absolute) URL of this page. It can be used when you navigate to this page object.

VerifyTitle and VerifyH1 are the triggers that, in the current case, are executed upon the page object initialization (after the navigation to the page). If the string value is not passed to these attributes, they use class name without the "Page" ending in title case, as "Sign In". It can be totally configured. Find out more about the triggers in the documentation.

Users Page

Users page

The Users page contains the table of the users with CRUD actions.

using Atata;

namespace SampleApp.UITests
{
    using _ = UsersPage;

    [VerifyTitle]
    [VerifyH1]
    public class UsersPage : Page<_>
    {
        public Button<UserEditWindow, _> New { get; private set; }

        public Table<UserTableRow, _> Users { get; private set; }

        public class UserTableRow : TableRow<_>
        {
            public Text<_> FirstName { get; private set; }

            public Text<_> LastName { get; private set; }

            public Text<_> Email { get; private set; }

            public Content<Office, _> Office { get; private set; }

            public Link<UserDetailsPage, _> View { get; private set; }

            public Button<UserEditWindow, _> Edit { get; private set; }

            [CloseConfirmBox]
            public Button<_> Delete { get; private set; }
        }
    }
}
UsersPage.cs

In the UsersPage class, you can see the usage of Table and TableRow controls. In UserTableRow class, the properties of type Text and Content by default are being searched by the column header (FindByColumnHeader attribute). It can also be configured. For example, the FirstName control will contain "John" value for the first row. The usage of the table will be shown in the test method below.

Delete button is marked with CloseConfirmBox trigger which accepts the confirmation window shown after the click on the button.

User Create/Edit Window

Users Create/Edit window

It is quite a simple Bootstrap popup window with two tabs and regular input controls.

using Atata;
using Atata.Bootstrap;

namespace SampleApp.UITests
{
    using _ = UserEditWindow;

    public class UserEditWindow : BSModal<_>
    {
        [FindById]
        public GeneralTabPane General { get; private set; }

        [FindById]
        public AdditionalTabPane Additional { get; private set; }

        [Term("Save", "Create")]
        public Button<UsersPage, _> Save { get; private set; }

        public class GeneralTabPane : BSTabPane<_>
        {
            public TextInput<_> FirstName { get; private set; }

            public TextInput<_> LastName { get; private set; }

            [RandomizeStringSettings("{0}@mail.com")]
            public TextInput<_> Email { get; private set; }

            public Select<Office?, _> Office { get; private set; }

            [FindByName]
            public RadioButtonList<Gender?, _> Gender { get; private set; }
        }

        public class AdditionalTabPane : BSTabPane<_>
        {
            public DateInput<_> Birthday { get; private set; }

            public TextArea<_> Notes { get; private set; }
        }
    }
}
UserEditWindow.cs

The UserEditWindow is inherited from BSModal page object. It is a component of Atata.Bootstrap package.

Save button is marked with Term("Save", "Create") attribute that specifies the values for the control search. It means that the button should be found by "Save" or "Cancel" content.

Gender and Office controls use the following enums:

namespace SampleApp.UITests
{
    public enum Gender
    {
        Male,
        Female
    }
}
Gender.cs
namespace SampleApp.UITests
{
    public enum Office
    {
        Berlin,
        London,
        NewYork,
        Paris,
        Rome,
        Tokio,
        Washington
    }
}
Office.cs

User Details Page

Users Details page

using System;
using Atata;

namespace SampleApp.UITests
{
    using _ = UserDetailsPage;

    public class UserDetailsPage : Page<_>
    {
        [FindFirst]
        public H1<_> Header { get; private set; }

        [FindByDescriptionTerm]
        public Text<_> Email { get; private set; }

        [FindByDescriptionTerm]
        public Content<Office, _> Office { get; private set; }

        [FindByDescriptionTerm]
        public Content<Gender, _> Gender { get; private set; }

        [FindByDescriptionTerm]
        public Content<DateTime?, _> Birthday { get; private set; }

        [FindByDescriptionTerm]
        public Text<_> Notes { get; private set; }
    }
}
UserDetailsPage.cs

Atata Assembly Settings

There is also a way to define global Atata settings for all page objects in scope of the assembly.

using Atata;

[assembly: Culture("en-us")]
[assembly: VerifyTitleSettings(Format = "{0} - Atata Sample App")]
AtataSettings.cs

Here we define the culture (is used by the controls like DateInput) and format of the page title, as all the pages on the testing website have a page title like "Sign In - Atata Sample App".

Base AutoTest Class

Now let's set up the Atata context for the testing. I prefer to create base test class where I put SetUp, TearDown and Login methods.

using Atata;
using NUnit.Framework;

namespace SampleApp.UITests
{
    [TestFixture]
    public class UITestFixture
    {
        [SetUp]
        public void SetUp()
        {
            AtataContext.Configure().
                UseChrome().
                    WithArguments("start-maximized").
                UseBaseUrl("https://demo.atata.io/").
                UseNUnitTestName().
                AddNUnitTestContextLogging().
                    WithoutSectionFinish().
                LogNUnitError().
                Build();
        }

        [TearDown]
        public void TearDown()
        {
            AtataContext.Current?.CleanUp();
        }

        protected UsersPage Login()
        {
            return Go.To<SignInPage>().
                Email.Set("admin@mail.com").
                Password.Set("abc123").
                SignIn.ClickAndGo();
        }
    }
}
UITestFixture.cs

Here, you can see a simple configuration of AtataContext in SetUp method. For more configuration options, please check the Getting Started / Set Up page in the docs.

As you can see in Login method, navigation starts from Go static class. To keep the example simple, I use hard-coded credentials here, that can easily be moved to App.config or Atata.json, for example.

UserTest

And finally, the test that will use all of the created above classes and enums.

using Atata;
using NUnit.Framework;

namespace SampleApp.UITests
{
    public class UserTests : UITestFixture
    {
        [Test]
        public void User_Create()
        {
            string firstName, lastName, email;
            Office office = Office.NewYork;
            Gender gender = Gender.Male;

            Login(). // Returns UsersPage.
                New.ClickAndGo(). // Returns UserEditWindow.
                    ModalTitle.Should.Equal("New User").
                    General.FirstName.SetRandom(out firstName).
                    General.LastName.SetRandom(out lastName).
                    General.Email.SetRandom(out email).
                    General.Office.Set(office).
                    General.Gender.Set(gender).
                    Save.ClickAndGo(). // Returns UsersPage.
                Users.Rows[x => x.FirstName == firstName && 
                    x.LastName == lastName].View.ClickAndGo(). // Returns UserDetailsPage.
                    Header.Should.Equal($"{firstName} {lastName}").
                    Email.Should.Equal(email).
                    Office.Should.Equal(office).
                    Gender.Should.Equal(gender).
                    Birthday.Should.Not.Exist().
                    Notes.Should.Not.Exist();
        }
    }
}
UserTests.cs

I prefer to use fluent page object pattern in the Atata tests. If you don't like such approach, use without fluent pattern.

You can use random or predefined values in the test, as you like.

The control verification starts with Should property. There is a set of extension methods for different controls like: Equal, Exist, StartWith, BeGreater, BeEnabled, HaveChecked, etc.

That's all. Build project, run test and verify how it works. Check the docs to find out more about Atata.

Logging

Test log

The example test produces the following log:

2018-06-05 14:32:15.0100 INFO Starting test: User_Create
2018-06-05 14:32:15.0325 TRACE Set up AtataContext
2018-06-05 14:32:15.0325 TRACE Set: BaseUrl=https://demo.atata.io/
2018-06-05 14:32:15.0335 TRACE Set: ElementFindTimeout=5s; ElementFindRetryInterval=0.5s
2018-06-05 14:32:15.0335 TRACE Set: WaitingTimeout=5s; WaitingRetryInterval=0.5s
2018-06-05 14:32:15.0335 TRACE Set: VerificationTimeout=5s; VerificationRetryInterval=0.5s
2018-06-05 14:32:17.8158 TRACE Set: Driver=ChromeDriver (alias=chrome)
2018-06-05 14:32:17.8738 INFO Go to "Sign In" page
2018-06-05 14:32:17.9154 INFO Go to URL "https://demo.atata.io/signin"
2018-06-05 14:32:18.7820 INFO Verify title should equal "Sign In - Atata Sample App"
2018-06-05 14:32:18.8005 INFO Verify "Sign In" <h1> heading should exist
2018-06-05 14:32:18.8697 INFO Set "admin@mail.com" to "Email" text input
2018-06-05 14:32:19.0071 INFO Set "abc123" to "Password" password input
2018-06-05 14:32:19.1228 INFO Click "Sign In" button
2018-06-05 14:32:19.2279 INFO Go to "Users" page
2018-06-05 14:32:19.2319 INFO Verify title should equal "Users - Atata Sample App"
2018-06-05 14:32:19.2364 INFO Verify "Users" <h1> heading should exist
2018-06-05 14:32:19.2701 INFO Click "New" button
2018-06-05 14:32:19.3615 INFO Go to "User Edit" modal
2018-06-05 14:32:19.3771 INFO Verify "Modal Title" element content should equal "New User"
2018-06-05 14:32:20.0445 INFO Set "fmlplblljjhiejp" to "General" tab pane's "First Name" text input
2018-06-05 14:32:20.2798 INFO Set "hafjfbogdjahepl" to "General" tab pane's "Last Name" text input
2018-06-05 14:32:20.4292 INFO Set "aiohbdfoleldepf@mail.com" to "General" tab pane's "Email" text input
2018-06-05 14:32:20.5988 INFO Set "New York" to "General" tab pane's "Office" select
2018-06-05 14:32:20.6028 TRACE Click "General" tab pane's "Office" select's "New York" option
2018-06-05 14:32:20.7410 INFO Set "Male" to "General" tab pane's "Gender" radio button list
2018-06-05 14:32:20.9197 INFO Click "Save" button
2018-06-05 14:32:21.0052 INFO Go to "Users" page
2018-06-05 14:32:21.0057 INFO Verify title should equal "Users - Atata Sample App"
2018-06-05 14:32:21.0092 INFO Verify "Users" <h1> heading should exist
2018-06-05 14:32:21.0550 INFO Click "Users" table's "FirstName == "fmlplblljjhiejp" && LastName == "hafjfbogdjahepl"" row's "View" link
2018-06-05 14:32:21.4388 INFO Go to "User Details" page
2018-06-05 14:32:21.4433 INFO Verify "Header" <h1> heading content should equal "fmlplblljjhiejp hafjfbogdjahepl"
2018-06-05 14:32:21.4886 INFO Verify "Email" element content should equal "aiohbdfoleldepf@mail.com"
2018-06-05 14:32:21.5409 INFO Verify "Office" element content should equal "New York"
2018-06-05 14:32:21.5923 INFO Verify "Gender" element content should equal "Male"
2018-06-05 14:32:21.6404 INFO Verify "Birthday" element should not exist
2018-06-05 14:32:21.6868 INFO Verify "Notes" element should not exist
2018-06-05 14:32:21.7958 INFO Clean up test context
2018-06-05 14:32:21.8697 INFO Finished test (7.091s)
2018-06-05 14:32:21.8702 INFO Pure test execution time: 3.978s

Download

Check the sources of Atata Framework on Atata GitHub page.

Get the sources of the demo test project on GitHub: Atata Sample App Tests. The demo project contains:

  • 20+ different auto-tests
  • Validation verification functionality
  • Logging functionality using NLog
  • Screenshot capturing

Contact

You can ask a question on Stack Overflow using atata tag or choose another contact option. Any feedback, issues and feature requests are welcome.

Atata Tutorials

History

  • December 1, 2016: Initial version posted
  • December 2, 2016: Sample sources added
  • April 4, 2017: Updated article content; added links to other Atata articles; updated sample sources
  • September 26, 2017: Updated sample sources to use Atata v0.14.0; updated article content
  • November 7, 2017: Updated sample sources to use Atata v0.15.0; updated article content
  • June 5, 2018: Updated sample sources to use Atata v0.17.0; updated article content
  • October 25, 2018: Updated sample sources to use Atata v1.0.0; updated "Features" and "Usage" sections content
  • May 15, 2019: Updated sample sources to use Atata v1.1.0; updated links to documentation that was moved to a new domain

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Yevgeniy Shunevych
Software Developer (Senior)
Ukraine Ukraine
C#/.NET Developer with 10+ years of experience in enterprise, web, desktop and automated testing software.
GitHub: https://github.com/YevgeniyShunevych

Comments and Discussions

 
QuestionVideos Pin
Satish Kumar Thirumalagiri16-Apr-19 9:25
memberSatish Kumar Thirumalagiri16-Apr-19 9:25 
QuestionLoad testing? Pin
Member 105605568-Jun-18 0:18
professionalMember 105605568-Jun-18 0:18 
AnswerRe: Load testing? Pin
Yevgeniy Shunevych8-Jun-18 11:01
memberYevgeniy Shunevych8-Jun-18 11:01 
QuestionError on loading Atata project Pin
waleedbadri18-Dec-17 23:56
memberwaleedbadri18-Dec-17 23:56 
AnswerRe: Error on loading Atata project Pin
Yevgeniy Shunevych22-Dec-17 5:22
memberYevgeniy Shunevych22-Dec-17 5:22 
QuestionSingle Page Apps (SPAs)? Pin
J Snyman26-Sep-17 23:30
memberJ Snyman26-Sep-17 23:30 
AnswerRe: Single Page Apps (SPAs)? Pin
Yevgeniy Shunevych27-Sep-17 1:45
memberYevgeniy Shunevych27-Sep-17 1:45 
QuestionWhat about windows desktop app? Pin
Win32nipuh6-Apr-17 2:08
professionalWin32nipuh6-Apr-17 2:08 
AnswerRe: What about windows desktop app? Pin
Yevgeniy Shunevych6-Apr-17 3:22
memberYevgeniy Shunevych6-Apr-17 3:22 
GeneralRe: What about windows desktop app? Pin
Win32nipuh6-Apr-17 3:49
professionalWin32nipuh6-Apr-17 3:49 
GeneralMy vote of 5 Pin
Fawad Raza5-Apr-17 3:21
memberFawad Raza5-Apr-17 3:21 
GeneralRe: My vote of 5 Pin
Yevgeniy Shunevych5-Apr-17 11:18
memberYevgeniy Shunevych5-Apr-17 11:18 
Question2 вопрос Pin
garinov@mail.ru9-Feb-17 7:14
membergarinov@mail.ru9-Feb-17 7:14 
AnswerRe: 2 вопрос Pin
Yevgeniy Shunevych12-Feb-17 6:12
memberYevgeniy Shunevych12-Feb-17 6:12 
QuestionА как это запустить? Pin
garinov@mail.ru9-Feb-17 5:08
membergarinov@mail.ru9-Feb-17 5:08 
AnswerRe: А как это запустить? Pin
Yevgeniy Shunevych12-Feb-17 6:09
memberYevgeniy Shunevych12-Feb-17 6:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 1 Dec 2016

Stats

129.2K views
722 downloads
80 bookmarked