Craftsman at Work

I'm Artur Karbone, coding software architect and independent IT consultant and this is my blog about craftsmanship, architecture, distributed systems, management and much more.

Read Your Functional Tests as a Book in C# Part 4 : A Context for Your Scenario

The Goal

In this series of posts I'm going to show how to leverage clean code principles when writing functional tests.

The Flow's Context

In my terminology a context is an abstraction, which holds all the flow's specific state and behavior.

Let me recall You the code from the previous part

  [TestFixture]
    public class BookForwarderScenario : BaseIntegrationTest
    {
        [Test]
        [ImpersonateRandomSystemPortalUser]
        public void BookSingleForwarderFlow()
        {            
           CustomerApp
                .NavigateToRegisterAndBook()
                .CreateBookForwarderContext()
                .ChooseFirstOrder()
                .LaunchBookingWizard()
                .SelectFirstForwarder()
                .GoToTheNextWizardStep()
                .SelectFirstContact()
                .GoToTheNextWizardStep()
                .SkipAgreedFreight()
                .Book()
                .EnsureNotification()
                .EnsureOrderHasGoneFromGrid()
                .GoToFollowUp()
                .EnsureBookedOrderExists();              
        }
    }

CustomerApp here is an abstraction that represents the application, which itself is a container holding test scenarios and some other thing. The application abstraction is especially handy, if You have multiple apps and need to test the integration between them.

CreateBookForwarderContext is an extension method, which creates the context.

public static BookForwarderFlowContext CreateBookForwarderContext(this IWebDriver webDriver)  
        {
            return new BookForwarderFlowContext(webDriver);
        }

Here is the code for the context. As I have mentioned before the class contains internal state to persist necessary data navigating through the flow and methods which describe abstract steps and hide low-level web driver acrobatics:

    public class BookForwarderFlowContext : BaseFlowContext
    {
        #region Constructors

        public BookForwarderFlowContext(IWebDriver webDriver)
            : base(webDriver)
        {
        }

        #endregion

        #region Internal State

        public string OrderNumber { get; set; }
        protected OrderRepository OrderRepository;
        public const string ExpectedDeletionNotification = "Order has been deleted";
        public const string ExpectedBookingNotification = "Order has been booked successfully";
        public const string ExpectedOrderAcceptedNotification = "Order has been successfully accepted";
        public const string ExpectedOrderRejectedNotification = "Order has been successfully rejected";
        public const string ExpectedInvoiceUpdateNotification = "Invoice has been checked";
        public const string ExpectedOrdeCanceledNotification = "Order has been successfully canceled";
        public const string HistoryMessage = "CorpManager@diatom.lv canceled Order.";
        public const string greenColor = "rgba(209, 245, 103, 1)";
        public const string redColor = "rgba(255, 0, 0, 1)";
        public string truckNumber = "Truck #";
        public string plannedLoadDate = "2019-12-31";
        public string plannedUnloadDate = "2019-12-31";
        public string actualLoadDate = "2019-12-31";
        public string actualUnloadDate = "2019-12-31";
        public string remembredForwarder = "";
        public string remembredForwarderLast = "";
        public const string phantomjs = "OpenQA.Selenium.PhantomJS.PhantomJSDriver";

        #endregion

        #region Flow Actions

        public BookForwarderFlowContext CancelOrder()
        {
            WebDriver
                .FindButtonByTextInDiv("Cancel")
                .Click();
            return this;
        }

        public BookForwarderFlowContext ViewSpecificOrderDetails()
        {
            WebDriver
                .FindFollowUpTable()
                .FindSpecificOrderRow(OrderNumber)
                .Click();
            return this;
        }

        .........
}

Posts in these series:

Part 1: The Tradegy

Part 2: Setting Up The Stage

Part 3: High Level of Abstraction

Part 4: A Context for Your Scenario

Part 5: Leverage Fluent Interface

comments powered by Disqus