引言
本文将讨论一个重要的软件工程原则:DRY(不要重复自己)。
为了证明这些概念在不同编程语言中的适用性,本文中我们将使用Playwright C# 项目,与上一篇文章中使用的TypeScript项目相反。
先决条件:
- 安装VS代码:https://code.visualstudio.com/download
- 安装最新的dotnet sdk:https://learn.microsoft.com/en-us/dotnet/core/install/windowsnet-installer
- 安装VS代码所需的扩展:https://learn.microsoft.com/en-us/dotnet/core/install/windows#install-with-visual-studio-code
- 安装PowerShell工具:https://devblogs.microsoft.com/powershell/introducing-powershell-as-net- global-tool/
项目设置:
- 在Visual Studio Code(VS Code)中,打开一个空文件夹。
-
在VS Code中,打开一个终端并运行以下命令来创建名为“PlaywrightPOM”的xUnit项目:
dotnet new xunit -n PlaywrightPOM
- 在终端中,导航到PlaywrightPOM文件夹。
- 通过在同一终端上运行以下命令,为PlayWright添加所需的软件包:
dotnet add package Microsoft.Playwright
- 在当前文件夹中创建下面三个文件夹:
Pages, Utilities, and Tests.
- 在终端中,运行以下命令来构建项目:
dotnet build
- 假设您有最新版本的.NET(写作时为8.0),在终端中运行以下命令来安装所需的各种PlayWright浏览器:
pwsh ./bin/Debug/net8.0/playwright.ps1 install
搭建一个简单的框架:
-
现在查看VS Code中的资源管理器窗口,您可以在PlaywrightPOM文件夹下看到GlobalUsings.cs文件(如果不存在,请创建一个)。将以下行添加到文件中:
global using Xunit;
global using Microsoft.Playwright;
global using System.Threading.Tasks;这是用来确保这些命名空间自动包含在项目中的所有文件中,简化了代码,并减少了对重复using语句的需求。在经常使用某些命名空间的大型项目中,这一点特别有用。 2. 创建一个Pages/BasePage.cs,并在文件中添加以下代码:
C# public class BasePage { protected IPage page; public BasePage(IPage page) { this.page = page; } public async Task NavigateToAsync(string url) { await page.GotoAsync(url); } public async Task ClickAsync(string selector) { await page.ClickAsync(selector); } public async Task<string> GetTextAsync(string selector){ return await page.InnerTextAsync(selector); } }
BasePage类封装了常见的网页交互操作,特定子页面就很容易继承它并扩展其功能。
这种方法促进了代码重用,并简化了Web自动化任务的实现。 3. 创建从BasePage继承的特定页面类Pages/HomePage.cs。例如,C# public class HomePage : BasePage { public HomePage(IPage page) : base(page) { } public async Task ClickLoginButtonAsync() { await ClickAsync("#loginButton"); } public async Task<string> GetWelcomeTextAsync() { return await GetTextAsync("#welcomeText"); } }
HomePage类封装了主页面的特定交互操作,这样给这部分Web应用程序编写和维护测试脚本就更容易了。
通过从BasePage继承,它促进了代码重用,并简化了常见web自动化任务的实现。 -
在Utilities/PlaywrightUtilities.cs中创建实用函数:
C# public static class PlaywrightUtilities { public static async Task<IPage> CreatePageAsync() { var playwright = await Playwright.CreateAsync(); var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = false }); var context = await browser.NewContextAsync(); return await context.NewPageAsync(); } }
CreatePageAsync方法封装了初始化Playwright核心、启动浏览器、创建浏览器上下文和打开新页面所需的步骤。
此实用方法简化了浏览器自动化任务的设置过程,使编写和维护测试脚本更容易。
让我们从忽略DRY原则开始:
创建一个新文件Tests/HomePageTestsWithoutDRY.cs,并添加以下代码:
public class HomePageTestsWithoutDRY
{
[Fact]
public async Task TestHomePageWithoutDRY()
{
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync(new
BrowserTypeLaunchOptions { Headless = false });
var context = await browser.NewContextAsync();
var page = await context.NewPageAsync();
await page.GotoAsync("https://example.com");
await page.ClickAsync("#loginButton");
var welcomeText = await page.InnerTextAsync("#welcomeText");
Assert.Equal("Welcome", welcomeText);
}
}
上面的测试方法演示了如何在单元测试中使用Playwright进行浏览器自动化,
但它不遵循DRY原则,因为它包含了重复设置代码,这些可以重构为可重用的方法或实用程序类。
现在,让我们实施DRY原则:
创建一个新的测试文件Tests/HomePageTestsWithDRY.cs,并添加以下代码:
public class HomePageTestsWithDRY
{
[Fact]
public async Task TestHomePageWithDRY()
{
var page = await PlaywrightUtilities.CreatePageAsync();
var homePage = new HomePage(page);
await homePage.NavigateToAsync("https://example.com");
await homePage.ClickLoginButtonAsync();
var welcomeText = await homePage.GetWelcomeTextAsync();
Assert.Equal("Welcome", welcomeText);
}
}
上面的测试方法同样演示了如何在单元测试中使用Playwright进行浏览器自动化,同时坚持DRY原则。
这里通过使用实用方法并在HomePage类中封装特定页面的交互,测试代码更加简洁、可读和可维护。
结语
正如你可能已经观察到的:
- 通过为共同活动创建可重用的实用函数和基类,DRY原理简化了测试代码并消除了重复。此外,定位器功能被移动到特定页面进行管理,因此管理起来会更容易。
- 通过减少示例中的代码行数,以及添加更多测试和可重用的功能,维护和升级将变得更加简单。这种减少将导致进一步的简化,使将来更容易维护和升级代码。
- 此外,从可读性/理解性的角度来看,很明显,DRY版本的测试对象是主页面,我们正在执行特定于主页的操作。
最后,我相信这篇文章可以帮助您提高自动化代码的效率、可重用性和可维护性。