Advanced Strategy Design Pattern in Automated Testing

Advanced Strategy Design Pattern in Automated Testing

Advanced Strategy Design Pattern C# Code

Test’s Test Case

Amazon Items Page

Login Existing Client Amazon

4. Fill Shipping Info

Fill Shipping Info Amazon

Select Payment Method Amazon

7. Validate the Order Summary

Validate Order Summary Amazon

public interface IOrderPurchaseStrategy
{
    void ValidateOrderSummary(string itemPrice, ClientPurchaseInfo clientPurchaseInfo);

    void ValidateClientPurchaseInfo(ClientPurchaseInfo clientPurchaseInfo);
}

This method is going to be used to validate the test prerequisite data passed to the pattern’s class. In SalesTaxOrderPurchaseStrategy if the shipping country is not United States an ArgumentException is thrown because the other methods of the class won’t be meaningful. The sales tax is applicable only for US.

public class SalesTaxOrderPurchaseStrategy : IOrderPurchaseStrategy
{
    public SalesTaxOrderPurchaseStrategy()
    {
        this.SalesTaxCalculationService = new SalesTaxCalculationService();
    }

    public SalesTaxCalculationService SalesTaxCalculationService { get; set; }

    public void ValidateOrderSummary(string itemsPrice, ClientPurchaseInfo clientPurchaseInfo)
    {
        States currentState = (States)Enum.Parse(typeof(States), clientPurchaseInfo.ShippingInfo.State);
        decimal currentItemPrice = decimal.Parse(itemsPrice);
        decimal salesTax = this.SalesTaxCalculationService.Calculate(currentItemPrice, currentState, clientPurchaseInfo.ShippingInfo.Zip);

        PlaceOrderPage.Instance.Validate().EstimatedTaxPrice(salesTax.ToString());
    }

    public void ValidateClientPurchaseInfo(ClientPurchaseInfo clientPurchaseInfo)
    {
        if (!clientPurchaseInfo.ShippingInfo.Country.Equals("United States"))
        {
            throw new ArgumentException("If the NoTaxesOrderPurchaseStrategy is used, the country should be set to United States because otherwise no sales tax is going to be applied.");
        }
    }
}

The same logic is implemented in the VatTaxOrderPurchaseStrategy, GiftOrderPurchase strategies. The only addition to these classes is the ValidateClientPurchaseInfo method. It can be used to validate that your strategies are utilized in the correct manner. There are a lot of companies where quality assurance automation engineers write the core framework (strategies, context classes) while the tests are written by less technical people. So such preventative measures can be considered in cases like that.

Reconstruct Text Strategies Context

First Version Basic Strategy Design Pattern Applied

public class PurchaseContext
{
    private readonly IOrderValidationStrategy orderValidationStrategy;

    public PurchaseContext(IOrderValidationStrategy orderValidationStrategy)
    {
        this.orderValidationStrategy = orderValidationStrategy;
    }

    public void PurchaseItem(string itemUrl, string itemPrice, ClientLoginInfo clientLoginInfo, ClientPurchaseInfo clientPurchaseInfo)
    {
        ItemPage.Instance.Navigate(itemUrl);
        ItemPage.Instance.ClickBuyNowButton();
        PreviewShoppingCartPage.Instance.ClickProceedToCheckoutButton();
        SignInPage.Instance.Login(clientLoginInfo.Email, clientLoginInfo.Password);
        ShippingAddressPage.Instance.FillShippingInfo(clientPurchaseInfo);
        ShippingAddressPage.Instance.ClickContinueButton();
        ShippingPaymentPage.Instance.ClickBottomContinueButton();
        ShippingPaymentPage.Instance.ClickTopContinueButton();
        this.orderValidationStrategy.ValidateOrderSummary(itemPrice, clientPurchaseInfo);
    }
}

Advanced Strategy Design Pattern Purchase Context Reconstruction

Improved Version Advanced Strategy Design Pattern Applied

public class PurchaseContext
{
    private readonly IOrderPurchaseStrategy[] orderpurchaseStrategies;

    public PurchaseContext(params IOrderPurchaseStrategy[] orderpurchaseStrategies)
    {
        this.orderpurchaseStrategies = orderpurchaseStrategies;
    }

    public void PurchaseItem(string itemUrl, string itemPrice, ClientLoginInfo clientLoginInfo, ClientPurchaseInfo clientPurchaseInfo)
    {
        this.ValidateClientPurchaseInfo(clientPurchaseInfo);

        ItemPage.Instance.Navigate(itemUrl);
        ItemPage.Instance.ClickBuyNowButton();
        PreviewShoppingCartPage.Instance.ClickProceedToCheckoutButton();
        SignInPage.Instance.Login(clientLoginInfo.Email, clientLoginInfo.Password);
        ShippingAddressPage.Instance.FillShippingInfo(clientPurchaseInfo);
        ShippingAddressPage.Instance.ClickDifferentBillingCheckBox(clientPurchaseInfo);
        ShippingAddressPage.Instance.ClickContinueButton();
        ShippingPaymentPage.Instance.ClickBottomContinueButton();
        ShippingAddressPage.Instance.FillBillingInfo(clientPurchaseInfo);
        ShippingAddressPage.Instance.ClickContinueButton();
        ShippingPaymentPage.Instance.ClickTopContinueButton();

        this.ValidateOrderSummary(itemPrice, clientPurchaseInfo);
    }

    public void ValidateClientPurchaseInfo(ClientPurchaseInfo clientPurchaseInfo)
    {
        foreach (var currentStrategy in orderpurchaseStrategies)
        {
            currentStrategy.ValidateClientPurchaseInfo(clientPurchaseInfo);
        }
    }

    public void ValidateOrderSummary(string itemPrice, ClientPurchaseInfo clientPurchaseInfo)
    {
        foreach (var currentStrategy in orderpurchaseStrategies)
        {
            currentStrategy.ValidateOrderSummary(itemPrice, clientPurchaseInfo);
        }
    }
}
public PurchaseContext(params IOrderPurchaseStrategy[] orderpurchaseStrategies)
{
    this.orderpurchaseStrategies = orderpurchaseStrategies;
}

Advanced Strategy Design Pattern- Usage in Tests

The usage of the advanced strategy design pattern in tests stays as smooth as before but now you can use multiple strategies combined.

First Version Basic Strategy Pattern Applied


public class OnlineStorePurchase_PurchaseStrategy_Tests
{
    
    public void SetupTest()
    {
        Driver.StartBrowser();
    }

    
    public void TeardownTest()
    {
        Driver.StopBrowser();
    }

    
    public void Purchase_SeleniumTestingToolsCookbook()
    {
        string itemUrl = "/Selenium-Testing-Cookbook-Gundecha-Unmesh/dp/1849515743";
        string itemPrice = "40.49";
        ClientPurchaseInfo clientPurchaseInfo = new ClientPurchaseInfo(
        new ClientAddressInfo()
        {
            FullName = "John Smith",
            Country = "United States",
            Address1 = "950 Avenue of the Americas",
            State = "New York",
            City = "New York City",
            Zip = "10001-2121",
            Phone = "00164644885569"
        })
        {
            GiftWrapping = Enums.GiftWrappingStyles.None
        };
        ClientLoginInfo clientLoginInfo = new ClientLoginInfo()
        {
            Email = "g3984159@trbvm.com",
            Password = "ASDFG_12345"
        };

        new PurchaseContext(new SalesTaxOrderValidationStrategy()).PurchaseItem(itemUrl, itemPrice, clientLoginInfo, clientPurchaseInfo);
    }
}

In the first version has been possible to pass only a single instance of the IOrderValidationStrategy.

Improved Version Using Advanced Strategy Design Pattern

For more detailed overview and usage of many more design patterns and best practices in automated testing, check my book “Design Patterns for High-Quality Automated Tests, C# Edition, High-Quality Tests Attributes, and Best Practices”.  You can read part of three of the chapters:

Defining High-Quality Test Attributes for Automated Tests

Benchmarking for Assessing Automated Test Components Performance

Generic Repository Design Pattern- Test Data Preparation

Improved Version Advanced Strategy Design Pattern Applied


public class OnlineStorePurchase_AdvancedPurchaseStrategy_Tests
{
    
    public void SetupTest()
    {
        Driver.StartBrowser();
    }

    
    public void TeardownTest()
    {
        Driver.StopBrowser();
    }

    
    public void Purchase_SeleniumTestingToolsCookbook()
    {
        string itemUrl = "/Selenium-Testing-Cookbook-Gundecha-Unmesh/dp/1849515743";
        string itemPrice = "40.49";
        var shippingInfo = new ClientAddressInfo()
        {
            FullName = "John Smith",
            Country = "United States",
            Address1 = "950 Avenue of the Americas",
            State = "New York",
            City = "New York City",
            Zip = "10001-2121",
            Phone = "00164644885569"
        };
        var billingInfo = new ClientAddressInfo()
        {
            FullName = "Anton Angelov",
            Country = "Bulgaria",
            Address1 = "950 Avenue of the Americas",
            City = "Sofia",
            Zip = "1672",
            Phone = "0894464647"
        };
        ClientPurchaseInfo clientPurchaseInfo = new ClientPurchaseInfo(billingInfo, shippingInfo)
        {
            GiftWrapping = Enums.GiftWrappingStyles.Fancy
        };
        ClientLoginInfo clientLoginInfo = new ClientLoginInfo()
        {
            Email = "g3984159@trbvm.com",
            Password = "ASDFG_12345"
        };

        new PurchaseContext(new SalesTaxOrderPurchaseStrategy(), new VatTaxOrderPurchaseStrategy(), new GiftOrderPurchaseStrategy())
        .PurchaseItem(itemUrl, itemPrice, clientLoginInfo, clientPurchaseInfo);
    }
}

Related Articles

Design Patterns

Page Objects- Partial Classes Page Sections- WebDriver C#

Editorial Note: I originally wrote this post for the Test Huddle Blog. You can check out the original here, at their site.

Page Objects- Partial Classes Page Sections- WebDriver C#

Design Architecture, Design Patterns

Failed Tests Аnalysis- Chain of Responsibility Design Pattern

After more than three months it is time for a new article part of the most successful Automate The Planet's series- Design Patterns in Automated Testing. In the

Failed Tests Аnalysis- Chain of Responsibility Design Pattern

Design Patterns

Black Hole Proxy Pattern for Reducing Test Instability

In this article, we will review the Black Hole Proxy Pattern. It tries to reduce test instability by getting rid of as many third-party uncertainties as possibl

Black Hole Proxy Pattern for Reducing Test Instability

Design Patterns

Serverless Execution of WebDriver Tests via Azure Functions

In this article part of the popular WebDriver Series, we will look into what serverless means and how we can apply in automated testing. Also, we talk about Azu

Serverless Execution of WebDriver Tests via Azure Functions

Design Patterns

Page Object Pattern in Automated Testing

In my new series of articles "Design Patterns in Automated Testing", I am going to present you the most useful techniques for structuring the code of your autom

Page Object Pattern in Automated Testing

Design Patterns

Use IoC Container to Create Page Object Pattern on Steroids

In my previous articles from the series "Design Patterns in Automated Testing", I explained in details how to make your test automation framework better through

Use IoC Container to Create Page Object Pattern on Steroids
Anton Angelov

About the author

Anton Angelov is Managing Director, Co-Founder, and Chief Test Automation Architect at Automate The Planet — a boutique consulting firm specializing in AI-augmented test automation strategy, implementation, and enablement. He is the creator of BELLATRIX, a cross-platform framework for web, mobile, desktop, and API testing, and the author of 8 bestselling books on test automation. A speaker at 60+ international conferences and researcher in AI-driven testing and LLM-based automation, he has been recognized as QA of the Decade and Webit Changemaker 2025.