Advanced Strategy Design Pattern C# Code
Test’s Test Case


4. Fill Shipping Info


7. Validate the Order Summary

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);
}
}

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.

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);
}
} 