65.9K
CodeProject 正在变化。 阅读更多。
Home

测试架构设计评估系统 - 基于Facade的测试

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2017 年 3 月 20 日

Ms-PL

5分钟阅读

viewsIcon

9415

我们将使用之前介绍的评估框架来评估使用 Facade(外观)设计模式的测试。找出评分以及评分背后的原因。

引言

在我之前的文章《测试与架构设计评估系统》中,我向大家介绍了系统测试架构设计的八项评估标准。为了全面理解这个系统,我将用它来评估几个实际的例子,为每个标准打分,并解释我的理由。我们首先要评估的是 Facade(外观)模式测试。如果你不熟悉 Facade(外观)设计模式,可以阅读我的文章《改进的自动化测试 Facade(外观)设计模式 v.2.0》。

Facade(外观)模式测试

我们测试框架的早期版本利用了 Facade(外观)设计模式。这是我们将要通过提出的评估系统进行评估的第一个设计。Facade(外观)是一个对象,它为更大的代码集合(如类库)提供了一个简化的接口。它使得软件库更容易使用和理解,可读性更高,并减少了对外部或其他代码的依赖。

Facade(外观)中的区域(Regions)

实际上并没有真正的缺点,因为它为子系统中的一组接口提供了一个统一的接口。然而,对我们来说最大的问题是 Facade(外观)文件的规模。它们变得非常庞大,可能有数千行代码。我们不得不在其中使用区域(regions)来分隔代码的不同部分。区域允许你指定一个代码块,在使用 Visual Studio Code 编辑器的代码大纲功能时,可以展开或折叠它。如图所示,在 Billing(账单)的 Facade(外观)中,使用了四个不同的区域来分隔元素映射属性、private 字段以及其余的方法。

改进的 Facade(外观)设计模式

这是我们负责创建购买的购物车 Facade(外观)的代码。我们决定以一种略有不同的方式使用 Facade(外观)设计模式。它结合了不同页面的方法来完成订单的向导流程。如果执行动作的顺序发生变化,我只需要在这里编辑即可。这将应用于使用该 Facade(外观)的测试。不同的测试用例通过传递给 Facade(外观)方法的不同参数来实现。这类 Facade(外观)的代码量要少得多,因为大部分逻辑由页面本身而不是 Facade(外观)来持有。

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

在测试中的使用

这是 Facade(外观)在测试中的一个示例用法。首先,我们需要初始化所有必需的参数。然后,你只需调用主要工作流的方法。

[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(外观)设计模式的优点

  • 隐藏复杂逻辑
  • 简化测试创建
  • 工作流更改 - 单一位置

Facade(外观)设计模式的缺点

  • 文件庞大
  • 构造函数巨大
  • 从测试主体看不清测试工作流
  • 影响大量测试
  • 新人难以适应

使用评估系统评估 Facade(外观)模式测试

可维护性

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

可维护性为“很好”(4)。对 Facade(外观)进行故障排除和添加新功能都很直接。然而,评分没有标记为“优秀”,因为通过对 Facade(外观)进行小的更改,很容易在现有测试中引入回归。

 Facade(外观)模式测试
可维护性4
可读性-
代码复杂度指数-
可用性-
灵活性-
学习曲线-
最少知识-

可读性

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

可读性被评为“差”(2)。与其他所有解决方案相比,测试包含的代码量要少得多。然而,由于你只从 Facade(外观)调用一个方法,用户并不清楚该方法在后台做了什么。此外,由于其庞大的规模,Facade(外观)相对难以阅读,并且在其中查找内容并非易事。

 Facade(外观)模式测试
可维护性4
可读性2
代码复杂度指数-
可用性-
灵活性-
学习曲线-
最少知识-

代码复杂度指数

Facade(外观)类别的指数为“差”(3),因为它们的规模很大,并且依赖于许多其他类,例如其他 Facade(外观)和许多页面。相反,测试类的大小相当短,并且只调用 Facade(外观)本身。

 Facade(外观)模式测试
可维护性4
可读性2
代码复杂度指数3
可用性-
灵活性-
学习曲线-
最少知识-

可用性

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

可用性为“很好”(4)。编写新测试非常直接。评分不是“优秀”,仅仅是因为用户需要提前初始化测试上下文。

 Facade(外观)模式测试
可维护性4
可读性2
代码复杂度指数3
可用性4
灵活性-
学习曲线-
最少知识-

灵活性

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

灵活性非常差(1)。如果更改现有工作流的某些部分,你将影响所有现有测试,并可能导致回归问题。如果需要创建自定义工作流,你必须添加自定义公共工作流方法,这会使已经庞大的 Facade(外观)变得更大。你无法在测试级别更改或定制已构建的工作流。

 Facade(外观)模式测试
可维护性4
可读性2
代码复杂度指数3
可用性4
灵活性1
学习曲线-
最少知识-

学习曲线

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(外观)模式测试
可维护性4
可读性2
代码复杂度指数3
可用性4
灵活性1
学习曲线3
最少知识-

最少知识

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(外观)可以访问整个测试上下文,而测试上下文通常非常庞大。并非所有方法都需要测试上下文中的所有信息。因此,评分被标记为“差”(2)。

 Facade(外观)模式测试
可维护性4
可读性2
代码复杂度指数3
可用性4
灵活性1
学习曲线3
最少知识2

在本系列的下一篇文章中,我将使用评估系统来评估行为驱动测试

你可以观看我专门介绍该系统的会议演讲,或下载完整的幻灯片

设计与架构

文章 测试架构设计评估系统 - Facade(外观)模式测试 最先出现在 Automate The Planet

所有图片均从 DepositPhotos.com 购买,不可免费下载和使用。
许可协议

© . All rights reserved.