在自动化测试的世界里,代码的组织和结构至关重要。良好的代码结构不仅可以提高测试的可读性,还能增强代码的可维护性和可扩展性。今天,将探讨一种流行的设计模式——页面对象模式(Page Object Pattern),它在Web自动化测试中被广泛应用。
页面对象模式的核心思想是将网页上的所有元素、操作和验证封装到一个单一的对象中,这个对象被称为页面对象(Page Object)。这样做的好处是,可以将测试逻辑与页面元素的定位逻辑分离,从而使得测试代码更加清晰和易于维护。
Selenium WebDriver是一个流行的自动化测试工具,它提供了一种内置的页面对象模式实现方式。可以通过以下步骤来使用这种模式:
首先,需要定义一个页面对象类,这个类包含了页面上所有元素的属性和可以执行的操作。例如,如果正在测试Bing搜索引擎,可以创建一个名为BingMainPage的页面对象类,其中包含了搜索框、搜索按钮和结果计数器等元素的属性。
public class BingMainPage {
private readonly IWebDriver driver;
private readonly string url = "http://www.bing.com/";
public BingMainPage(IWebDriver browser) {
this.driver = browser;
PageFactory.InitElements(browser, this);
}
[FindsBy(How = How.Id, Using = "sb_form_q")]
public IWebElement SearchBox { get; set; }
[FindsBy(How = How.Id, Using = "sb_form_go")]
public IWebElement GoButton { get; set; }
[FindsBy(How = How.Id, Using = "b_tween")]
public IWebElement ResultsCountDiv { get; set; }
public void Navigate() {
this.driver.Navigate().GoToUrl(this.url);
}
public void Search(string textToType) {
this.SearchBox.Clear();
this.SearchBox.SendKeys(textToType);
this.GoButton.Click();
}
public void ValidateResultsCount(string expectedCount) {
Assert.IsTrue(this.ResultsCountDiv.Text.Contains(expectedCount), "The results DIV doesn't contain the specified text.");
}
}
在这个例子中,使用了Selenium WebDriver的PageFactory类来初始化页面上的元素。PageFactory.InitElements方法会在页面首次加载时初始化所有元素。
接下来,可以在测试类中使用这个页面对象。测试类包含了与特定页面相关的所有测试用例。例如,可以创建一个名为BingTests的测试类,其中包含了一个BingMainPage对象的实例,并使用这个对象来执行搜索操作和验证结果。
[TestClass]
public class BingTests {
public IWebDriver Driver { get; set; }
public WebDriverWait Wait { get; set; }
[TestInitialize]
public void SetupTest() {
this.Driver = new FirefoxDriver();
this.Wait = new WebDriverWait(this.Driver, TimeSpan.FromSeconds(30));
}
[TestCleanup]
public void TeardownTest() {
this.Driver.Quit();
}
[TestMethod]
public void SearchTextInBing_First() {
BingMainPage bingMainPage = new BingMainPage(this.Driver);
bingMainPage.Navigate();
bingMainPage.Search("Automate The Planet");
bingMainPage.ValidateResultsCount("264,000 RESULTS");
}
}
页面对象模式的主要优点是提高了代码的可读性和可维护性。它遵循了DRY(不要重复自己)和单一责任原则。通过这种方式,可以构建出易于维护的测试代码,而不需要直接使用元素定位器。
除了使用Selenium WebDriver内置的页面对象模式实现方式,还可以手动创建页面对象类。这种方法不需要Selenium.Support NuGet包。可以将页面上的所有元素放在一个新的元素映射类中,并将所有验证方法放在一个单独的验证类中。
public class BingMainPageElementMap {
private readonly IWebDriver browser;
public BingMainPageElementMap(IWebDriver browser) {
this.browser = browser;
}
public IWebElement SearchBox {
get {
return this.browser.FindElement(By.Id("sb_form_q"));
}
}
public IWebElement GoButton {
get {
return this.browser.FindElement(By.Id("sb_form_go"));
}
}
public IWebElement ResultsCountDiv {
get {
return this.browser.FindElement(By.Id("b_tween"));
}
}
}
public class BingMainPageValidator {
private readonly IWebDriver browser;
public BingMainPageValidator(IWebDriver browser) {
this.browser = browser;
}
protected BingMainPageElementMap Map {
get {
return new BingMainPageElementMap(this.browser);
}
}
public void ResultsCount(string expectedCount) {
Assert.IsTrue(this.Map.ResultsCountDiv.Text.Contains(expectedCount), "The results DIV doesn't contain the specified text.");
}
}
最后,可以将所有类组合在一起,形成一个完整的页面对象。
public class BingMainPage {
private readonly IWebDriver browser;
private readonly string url = "http://www.bing.com/";
public BingMainPage(IWebDriver browser) {
this.browser = browser;
}
protected BingMainPageElementMap Map {
get {
return new BingMainPageElementMap(this.browser);
}
}
public BingMainPageValidator Validate() {
return new BingMainPageValidator(this.browser);
}
public void Navigate() {
this.browser.Navigate().GoToUrl(this.url);
}
public void Search(string textToType) {
this.Map.SearchBox.Clear();
this.Map.SearchBox.SendKeys(textToType);
this.Map.GoButton.Click();
}
}
在测试类中使用这种页面对象模式结构的方式与之前相同。不过,更喜欢这种解决方案,因为它更严格地遵循了SOLID原则。在这个解决方案中,不同的类具有更强的内聚性。