selenium-webdriver
페이지 개체 모델
수색…
소개
By
클래스를 사용하여 Selenium에서 찾을 수 있습니다. 이러한 로케이터와 상호 작용은 중복 된 코드를 피하고 유지 관리를 쉽게하기 위해 페이지 객체 내에 배치하는 것이 가장 좋습니다. 그것은 WebElements
캡슐화하고 페이지 (또는 웹 응용 프로그램의 페이지 일부)에서 동작 및 반환 정보를 포함한다고 가정합니다.
비고
페이지 객체 모델은 웹 페이지의 특정보기에 대한 인터페이스 역할을하는 객체 지향 클래스를 작성하는 패턴입니다. 해당 페이지 클래스의 메소드를 사용하여 필요한 조치를 수행합니다. 몇 년 전, 테스트 클래스에서 웹 페이지의 HTML 코드를 직접 조작하여 유지 보수하기가 매우 어려웠습니다. UI 변경에 취약했습니다.
그러나 페이지 객체 패턴의 방식으로 코드를 구성하면 애플리케이션 별 API가 제공되므로 HTML을 파고 들지 않고도 페이지 요소를 조작 할 수 있습니다. 엄지의 기본적인 Rue는 페이지 객체가 인간이 웹 페이지에서 할 수있는 모든 것을 가지고 있어야한다고 말합니다. 예를 들어, 웹 페이지의 텍스트 필드에 액세스하려면 모든 수정을 수행 한 후에 텍스트를 가져 와서 문자열을 반환하는 메소드가 있어야합니다.
페이지 객체를 디자인 할 때 유의해야 할 중요한 몇 가지 사항은 다음과 같습니다.
페이지 객체는 일반적으로 페이지에 대해서만 작성하면 안되지만 중요한 페이지 요소에 맞게 작성해야합니다. 예를 들어 학계의 여러 차트를 표시하는 여러 탭이있는 페이지는 탭 수와 동일한 페이지 수를 가져야합니다.
한 뷰에서 다른 뷰로 이동하면 페이지 클래스의 인스턴스를 반환해야합니다.
특정보기 또는 웹 페이지에만 있어야하는 유틸리티 메소드는 해당 페이지 클래스에만 속해야합니다.
어서션 메쏘드는 페이지 클래스에 의해 다루어 져서는 안되며, 부울을 반환하는 메소드를 가질 수는 있지만 거기서 검증하지는 마십시오. 예를 들어 사용자의 전체 이름을 확인하려면 부울 값을 가져 오는 메소드를 가질 수 있습니다.
public boolean hasDisplayedUserFullName (String userFullName) { return driver.findElement(By.xpath("xpathExpressionUsingFullName")).isDisplayed(); }
웹 페이지가 iframe을 기반으로하는 경우 iframe에도 페이지 클래스를 사용하는 것을 선호합니다.
페이지 객체 패턴의 장점 :
- 테스트 코드와 페이지 코드를 명확하게 구분
- 웹 페이지의 UI가 변경된 경우 여러 곳에서 코드를 변경할 필요가 없습니다. 페이지 클래스에서만 변경하십시오.
- 흩어진 요소 로케이터가 없습니다.
- 코드를 이해하기 쉽게 만든다.
- 손쉬운 유지 보수
소개 (Java 사용)
페이지 객체 패턴을 기반으로 로그인 테스트를 수행하는 예제는 다음과 같습니다.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
/**
* Class which models the view of Sign-In page
*/
public class SignInPage {
@FindBy(id="username")
private usernameInput;
@FindBy(id="password")
private passwordInput;
@FindBy(id="signin")
private signInButton;
private WebDriver driver;
public SignInPage(WebDriver driver) {
this.driver = driver;
}
/**
* Method to perform login
*/
public HomePage performLogin(String username, String password) {
usernameInput.sendKeys(username);
passwordInput.sendKeys(password);
signInButton.click();
return PageFactory.initElements(driver, HomePage.class);
}
}
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
/**
* Class which models the view of home page
*/
public class HomePage {
@FindBy(id="logout")
private logoutLink;
private WebDriver driver;
public HomePage(WebDriver driver) {
this.driver = driver;
}
/**
* Method to log out
*/
public SignInPage logout() {
logoutLink.click();
wait.ForPageToLoad();
return PageFactory.initElements(driver, SignInPage.class);
}
}
/**
* Login test class
*/
public class LoginTest {
public void testLogin() {
SignInPage signInPage = new SignInPage(driver);
HomePage homePage = signInPage.login(username, password);
signInPage = homePage.logout();
}
}
기음#
페이지 객체는 동작을 포함해야하고, 어설 션을위한 정보를 리턴해야하며 초기화시 페이지 준비 상태 메소드를위한 메소드를 포함해야합니다. Selenium은 주석을 사용하여 Page Object를 지원합니다. C #에서는 다음과 같습니다.
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.Generic;
public class WikipediaHomePage
{
private IWebDriver driver;
private int timeout = 10;
private By pageLoadedElement = By.ClassName("central-featured-logo");
[FindsBy(How = How.Id, Using = "searchInput")]
[CacheLookup]
private IWebElement searchInput;
[FindsBy(How = How.CssSelector, Using = ".pure-button.pure-button-primary-progressive")]
[CacheLookup]
private IWebElement searchButton;
public ResultsPage Search(string query)
{
searchInput.SendKeys(query);
searchButton.Click();
}
public WikipediaHomePage VerifyPageLoaded()
{
new WebDriverWait(driver, TimeSpan.FromSeconds(timeout)).Until<bool>((drv) => return drv.ExpectedConditions.ElementExists(pageLoadedElement));
return this;
}
}
노트:
-
CacheLookup
은 요소를 캐시에 저장하고 각 호출에 대해 새 요소를 반환합니다. 이렇게하면 성능은 향상되지만 동적으로 변경되는 요소에는 적합하지 않습니다. -
searchButton
에는 2 개의 클래스 이름과 ID가 없으므로 클래스 이름 또는 ID를 사용할 수 없습니다. - 내 로케이터가 개발자 도구 (Chrome 용)를 사용하여 원하는 요소를 반환하고 다른 브라우저에서는 FireBug 또는 이와 유사한 것을 사용할 수 있는지 확인했습니다.
-
Search()
클릭으로 다른 페이지로 리디렉션 될 때Search()
메서드는 다른 페이지 객체 (ResultsPage
)를 반환합니다.
모범 사례 페이지 개체 모델
- 머리글과 바닥 글에 대해 별도의 파일을 만듭니다 (모든 페이지에 공통적이며 단일 페이지의 일부로 만드는 것은 의미가 없습니다)
- 공통 요소 (검색 / 뒤로 / 다음 등)를 별도의 파일로 유지하십시오 (아이디어는 모든 종류의 중복을 제거하고 분리를 논리적으로 유지하는 것입니다)
- 드라이버의 경우 별도의 드라이버 클래스를 만들고 모든 페이지에서 액세스 할 수 있도록 드라이버를 정적으로 유지하는 것이 좋습니다. (내 모든 웹 페이지에서 DriverClass를 확장했습니다.)
- PageObjects에서 사용되는 함수는 빈도와 호출 방법을 염두에두고 가능한 가장 작은 청크로 분류됩니다 (로그인은 enterUsername 및 enterPassword 함수로 나눌 수 있지만 계속 유지하는 방식 임) Login 함수는 대개의 경우 enterUsername 및 enterPassword 함수에 대한 별도의 호출 대신 Login 함수가 호출되기 때문에 더 논리적입니다.
- PageObjects 자체를 사용하면 elementLocators에서 Test 스크립트를 분리 할 수 있습니다.
- 별도의 유틸리티 폴더에 유틸리티 기능이 있습니다 (예 : DateUtil, excelUtils 등)
- 별도의 conf 폴더에 구성을 지정하십시오 (예 : 테스트를 실행해야하는 환경 설정, 출력 및 입력 폴더 구성)
- 실패시 screenCapture 통합
- DriverClass에서 정적 대기 변수를 암시 적 대기 시간과 함께 사용하십시오. 항상 wait.until (ExpectedConditions)과 같은 정적 대기보다는 조건부 대기를 시도하십시오. 이렇게하면 대기가 실행을 불필요하게 늦추지 않습니다.