Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Assessment System for Tests Architecture Design - Facade Based Tests

5.00/5 (2 votes)
19 Mar 2017Ms-PL5 min read 9K  
We will use the previously presented assessment framework to evaluate tests that use the Facade Design Pattern. Find the ratings and reasoning behind them.

Introduction

In my previous article, Assessment System for Tests & Architecture Design, I presented to you eight criteria for system tests architecture design assessment. To understand the system fully, I am going to use it to evaluate a couple of real-world examples, assign ratings to them for each criterion and tell you my reasoning behind them. The first type of tests that we will assess is the facade based tests. If you are not familiar with the Facade Design Pattern, you can check my article, Improved Facade Design Pattern in Automated Testing v.2.0.

Facade Based Tests

The initial versions of our tests framework utilized the facade design pattern. This is the first design that we are going to evaluate through the proposed assessment system. A facade is an object that provides a simplified interface to a larger body of code, such as a class library. It makes the software library easier to use and understand, is more readable, and reduces dependencies on external or other code.

Regions in Facades

There are not any real drawbacks, as it provides a unified interface to a set of interfaces in a subsystem. However, the biggest problem for us was the size of the facade files. They got enormous, like thousands of lines of code. We had to use regions inside to separate the different parts of the code. Regions let you specify a block of code that you can expand or collapse when using the outlining feature of the Visual Studio Code Editor. As depicted in the image, in the Billing facade, four different regions were used for separating the element map properties, the private fields, and the rest of the methods.

Image 1

Improved Facade Design Pattern

This is the code of our shopping cart facade responsible for creating purchases. We decided to use the facade design pattern in a little different way. It combines the different pages' methods to complete the wizard of the order. If there is a change in the order of the executed actions, I can edit it only here. It will apply to tests that are using the facade. The different test cases are accomplished through the different parameters passed to the facade's methods. These types of facades contain much less code because most of the logic is held by the pages instead of the facade itself.

C#
public class ShoppingCart
{
    private readonly ItemPage itemPage;
    private readonly PreviewShoppingCartPage previewShoppingCartPage;
    private readonly SignInPage signInPage;
    private readonly ShippingAddressPage shippingAddressPage;
    private readonly ShippingPaymentPage shippingPaymentPage;
    private readonly PlaceOrderPage placeOrderPage;

    public ShoppingCart(
        ItemPage itemPage,
        PreviewShoppingCartPage previewShoppingCartPage,
        SignInPage signInPage,
        ShippingAddressPage shippingAddressPage,
        ShippingPaymentPage shippingPaymentPage,
        PlaceOrderPage placeOrderPage)
    {
        this.itemPage = itemPage;
        this.previewShoppingCartPage = previewShoppingCartPage;
        this.signInPage = signInPage;
        this.shippingAddressPage = shippingAddressPage;
        this.shippingPaymentPage = shippingPaymentPage;
        this.placeOrderPage = placeOrderPage;
    }

    public void PurchaseItem(
        string itemUrl,
        string itemPrice,
        ClientLoginInfo clientLoginInfo,
        ClientPurchaseInfo clientPurchaseInfo)
    {
        this.itemPage.Navigate(itemUrl);
        this.itemPage.ClickBuyNowButton();
        this.previewShoppingCartPage.ClickProceedToCheckoutButton();
        this.signInPage.Login(clientLoginInfo.Email, clientLoginInfo.Password);
        this.shippingAddressPage.FillShippingInfo(clientPurchaseInfo);
        this.shippingAddressPage.ClickDifferentBillingCheckBox(clientPurchaseInfo);
        this.shippingAddressPage.ClickContinueButton();
        this.shippingPaymentPage.ClickBottomContinueButton();
        this.shippingAddressPage.FillBillingInfo(clientPurchaseInfo);
        this.shippingAddressPage.ClickContinueButton();
        this.shippingPaymentPage.ClickTopContinueButton();
        double totalPrice = double.Parse(itemPrice);
        this.placeOrderPage.AssertOrderTotalPrice(totalPrice);
    }
}

Usage in Tests

This is a sample usage of the facade in tests. First, we need to initialize all required parameters. After that, you simply call the main workflow's method.

C#
[TestMethod]
public void Purchase_ShoppingCartFacade()
{
    var itemUrl = "/Selenium-Testing-Cookbook-Gundecha-Unmesh/dp/1849515743";
    var itemPrice = "40.49";
    var 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"
        });
    clientPurchaseInfo.CouponCode = "99PERDIS";
    var clientLoginInfo = new ClientLoginInfo()
    {
        Email = "g3984159@trbvm.com",
        Password = "ASDFG_12345"
    };
    var shoppingCart = container.Resolve<ShoppingCart>();
    shoppingCart.PurchaseItem(itemUrl, itemPrice, clientLoginInfo, clientPurchaseInfo);
}

Facade Design Pattern Pros

  • Hide complex logic
  • Simplify tests' creation
  • Workflow's changes- single place

Facade Design Pattern Cons

  • Enormous files
  • Huge constructors
  • Not clear tests' workflow from test's body
  • Affect a large number of tests
  • Hard to orient- new people

Evaluate Facade Based Tests- Assessment System

Maintainability

C#
public void PurchaseItem(
    string itemUrl,
    string itemPrice,
    ClientLoginInfo clientLoginInfo,
    ClientPurchaseInfo clientPurchaseInfo)
{
    this.itemPage.Navigate(itemUrl);
    this.itemPage.ClickBuyNowButton();
    this.previewShoppingCartPage.ClickProceedToCheckoutButton();
    this.signInPage.Login(clientLoginInfo.Email, clientLoginInfo.Password);
    this.shippingAddressPage.FillShippingInfo(clientPurchaseInfo);
    this.shippingAddressPage.ClickDifferentBillingCheckBox(clientPurchaseInfo);
    this.shippingAddressPage.ClickContinueButton();
    this.shippingPaymentPage.ClickBottomContinueButton();
    this.shippingAddressPage.FillBillingInfo(clientPurchaseInfo);
    this.shippingAddressPage.ClickContinueButton();
    this.shippingPaymentPage.ClickTopContinueButton();
    double totalPrice = double.Parse(itemPrice);
    this.placeOrderPage.AssertOrderTotalPrice(totalPrice);
}

The maintainability is Very Good (4). The troubleshooting and adding new features to the facades is straightforward. However, the rating is not marked as Excellent because you can easily introduce a regression in the existing tests with small changes in the facade.

 Facade Based Tests
Maintainability4
Readability-
Code Complexity Index-
Usability-
Flexibility-
Learning Curve-
Least Knowledge-

Readability

C#
var shoppingCart = container.Resolve<ShoppingCart>();
shoppingCart.PurchaseItem(itemUrl, itemPrice, clientLoginInfo, clientPurchaseInfo);

The readability is evaluated as Poor (2). The tests contain much less code compared to all other solutions. However, as you call only a single method from the facade in the tests, it is not clear to the user what this method is doing under the hood. Further, due to their large sizes, the facades are relatively unreadable and it is not an easy job to find something inside them.

 Facade Based Tests
Maintainability4
Readability2
Code Complexity Index-
Usability-
Flexibility-
Learning Curve-
Least Knowledge-

Code Complexity Index

The facade classes have a poor (3) index because they are large in size and they depend on lots of other classes such as other facades and lots of pages. On the opposite, the tests' classes are fairly short in size and call only the facade itself.

 Facade Based Tests
Maintainability4
Readability2
Code Complexity Index3
Usability-
Flexibility-
Learning Curve-
Least Knowledge-

Usability

C#
var itemUrl = "/Selenium-Testing-Cookbook-Gundecha-Unmesh/dp/1849515743";
var itemPrice = "40.49";
var 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"
    });
clientPurchaseInfo.CouponCode = "99PERDIS";
var clientLoginInfo = new ClientLoginInfo()
{
    Email = "g3984159@trbvm.com",
    Password = "ASDFG_12345"
};

The usability is Very Good (4). The writing of new tests is straightforward. The rating is not Excellent just because the user has to initialize the tests context upfront.

 Facade Based Tests
Maintainability4
Readability2
Code Complexity Index3
Usability4
Flexibility-
Learning Curve-
Least Knowledge-

Flexibility

C#
public void PurchaseItem(
    string itemUrl,
    string itemPrice,
    ClientLoginInfo clientLoginInfo,
    ClientPurchaseInfo clientPurchaseInfo)
{
    this.itemPage.Navigate(itemUrl);
    this.itemPage.ClickBuyNowButton();
    this.previewShoppingCartPage.ClickProceedToCheckoutButton();
    this.signInPage.Login(clientLoginInfo.Email, clientLoginInfo.Password);
    this.shippingAddressPage.FillShippingInfo(clientPurchaseInfo);
    this.shippingAddressPage.ClickDifferentBillingCheckBox(clientPurchaseInfo);
    this.shippingAddressPage.ClickContinueButton();
    this.shippingPaymentPage.ClickBottomContinueButton();
    this.shippingAddressPage.FillBillingInfo(clientPurchaseInfo);
    this.shippingAddressPage.ClickContinueButton();
    this.shippingPaymentPage.ClickTopContinueButton();
    double totalPrice = double.Parse(itemPrice);
    this.placeOrderPage.AssertOrderTotalPrice(totalPrice);
}

The flexibility is Very Poor (1). If you change some of the existing workflows, you will affect all existing tests and possibly create regression issues. If you need to create custom workflow you have to add custom public workflow method which makes the already large facade even bigger. You cannot change or customize the already constructed workflows on a test level.

 Facade Based Tests
Maintainability4
Readability2
Code Complexity Index3
Usability4
Flexibility1
Learning Curve-
Least Knowledge-

Learning Curve

C#
var itemUrl = "/Selenium-Testing-Cookbook-Gundecha-Unmesh/dp/1849515743";
var itemPrice = "40.49";
var 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"
    });
clientPurchaseInfo.CouponCode = "99PERDIS";
var clientLoginInfo = new ClientLoginInfo()
{
    Email = "g3984159@trbvm.com",
    Password = "ASDFG_12345"
};
var shoppingCart = container.Resolve<ShoppingCart>();
shoppingCart.PurchaseItem(itemUrl, itemPrice, clientLoginInfo, clientPurchaseInfo);

There are two tricky parts with the approach. First, you should know how to initialize the test context correctly. Secondly, if there are multiple public workflow methods, you should be aware which is the most appropriate to call.

 Facade Based Tests
Maintainability4
Readability2
Code Complexity Index3
Usability4
Flexibility1
Learning Curve3
Least Knowledge-

Least Knowledge

C#
var itemUrl = "/Selenium-Testing-Cookbook-Gundecha-Unmesh/dp/1849515743";
var itemPrice = "40.49";
var 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"
    });
clientPurchaseInfo.CouponCode = "99PERDIS";
var clientLoginInfo = new ClientLoginInfo()
{
    Email = "g3984159@trbvm.com",
    Password = "ASDFG_12345"
};
var shoppingCart = container.Resolve<ShoppingCart>();
shoppingCart.PurchaseItem(itemUrl, itemPrice, clientLoginInfo, clientPurchaseInfo);

The facade has access to the whole test context which is usually enormous in size. Not all methods need all of the information present in the test context. Because of that, the rating is marked as poor (2).

 Facade Based Tests
Maintainability4
Readability2
Code Complexity Index3
Usability4
Flexibility1
Learning Curve3
Least Knowledge2

In my next article from the series, I will use the assessment system to evaluate the behavior based tests.

You can watch my conference talk dedicated to the system or download the whole slide deck.

Design & Architecture

The post Assessment System for Tests Architecture Design- Facade Based Tests appeared first on Automate The Planet.

All images are purchased from DepositPhotos.com and cannot be downloaded and used for free.
License Agreement

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)