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





5.00/5 (2投票s)
我们将使用之前介绍的评估框架来评估使用 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 |
在本系列的下一篇文章中,我将使用评估系统来评估行为驱动测试。
你可以观看我专门介绍该系统的会议演讲,或下载完整的幻灯片。
设计与架构
- 创建混合测试框架 – Selenium 驱动控件
- 创建混合测试框架 – Selenium Driver 实现
- 创建混合测试自动化框架——接口契约
- 创建混合测试框架 – 测试框架驱动实现
- 创建混合测试框架 – 测试框架驱动控件
- 创建混合测试框架 – 高级元素查找扩展
- 创建混合测试框架 – 动态配置执行引擎
- 创建混合测试框架 - 抽象单元测试框架
文章 测试架构设计评估系统 - Facade(外观)模式测试 最先出现在 Automate The Planet。
所有图片均从 DepositPhotos.com 购买,不可免费下载和使用。
许可协议