반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

Selenium 2/WebDriver Quick Tips: Page Object Navigation Strategies
   
   


automated web testing (테스트 자동화) 에서 Page Object는 애플리케이션의 웹 페이지를 나타내는 클래스 혹은 객체를 말합니다. Page Object는 개발자가 웹페이지와 상호작용하는 기술적이고 상세한 내용들을 따로 떼어내서 다루기 때문에 좀 더 가독성 있고 실제 구현해야 할 비지니스에 집중할 수 있는 개발환경을 제공합니다.
  

두가지 장점으로 정리하자면 아래와 같습니다.

    * 가독성 높은 테스트 코드
    * 한 장소에 page access logic을 따로 만들어서 사용해 유지보수에도 훨씬 유리하다.



이 Page Object를 사용하지 않을 경우의 테스트는 아래와 같습니다.


    @Test
    public void shouldBeAbleToSearchForCats() {

        driver.get("http://www.trademe.co.nz");
        driver.findElement(By.id("searchString"))
                 .sendKeys("cats");
        driver.findElement(
                  By.cssSelector("button[value='Search']"))
                  .click();

        assertThat(driver.getTitle())
                         .contains("cats for sale");
        List titleElements
           = driver.findElements(
                        By.cssSelector(".listingTitle"));
        List adTitles = Lists.newArrayList();
        for(WebElement titleElement : titleElements) {
            adTitles.add(titleElement.getText());
        }

        assertThat(adTitles).isNotEmpty();
        for(String title : adTitles) {
            assertThat(title)
                 .containsIgnoringCase("cats");
        }
    }


이것을 Page Object를 사용해서 만들면 아래처럼 만들 수 있습니다.
   


    SearchPage searchPage;
    ResultsPage resultsPage;
           
    @Test
    public void shouldBeAbleToSearchForCats() {
        searchPage.open();
        searchPage.searchFor("cats");
        resultsPage.shouldDisplayTitlesWith("cats");
    }



이 경우 SearchPage 클래스는 아래와 같이 Thucydides 를 사용할 겁니다.



@DefaultUrl("http://www.trademe.co.nz")
public class SearchPage extends PageObject {

    @FindBy(id = "searchString")
    WebElement searchField;

    @FindBy(css = "button[value='Search']")
    WebElement searchButton;

    @FindBy(id = "main-box-categories")
    WebElement categoriesList;

    public SearchPage(WebDriver driver) {
        super(driver);
    }

    public void searchFor(String searchTerms) {
        searchField.sendKeys(searchTerms);
        searchButton.click();
    }

    public void selectsCategory(String category) {
        categoriesList.findElement(
            By.linkText(category)).click();
    }
}


Page Object를 가지고 navigation을 해야 될 때 사용되는 일반적인 방법은 새로운 페이지로 navigate 하고 이 page에 대한 Page Object를 return 하는 메소드를 만드는 것입니다. 예를 들어 serchFor 메소드 리스트는 아래와 같이 작성되어야 할 겁니다.


   

public void searchFor(String searchTerms) {
        searchField.sendKeys(searchTerms);
        searchButton.click();
        return switchTo(ResultsPage.class);
    }



만약 operation이 새로운 페이지로 navigate 하지 않는다면 이 Page Object 는 간단히 자기 자신을 return 하면 됩니다.


   

public SearchPage selectsCategory(String category) {
        categoriesList.findElement(
            By.linkText(category)).click();
        return this;
    }



이 접근법은 두가지 장점이 있습니다. 첫번째로 테스트의 가독성이 좀 더 편하게 됩니다.


   

SearchPage searchPage;
    ResultsPage resultsPage;
           
    @Test
    public void shouldBeAbleToSearchForCats() {
        searchPage.open();
        searchPage.searchFor("cats")
                  .selectsCategory("Pets & Animals")
                  .shouldDisplayTitlesWith("cats");
    }



또한 이 Page Objects 의 내용을 잘 몰라도 그냥 이것을 extend 해서 사용하면 됩니다. IDE 가 각 action 이후에 어떤 operation이 가능한지 그 리스트를 보여줄 겁니다.



이 접근법은 page navigation이 분명하게 정의되고 변화없이 안정적인 어플리케이션의 경우 아주 유용하게 사용될 수 있습니다. 어떤 어플리케이션들에서는 navigation이 분명하지 않은 경우가 있습니다. non-trivial navigation logic 에 따라 여러 다른 screen으로 이동하거나 (GWT 같은 AJAX-heavy 프레임워크를 사용하는 어플리케이션의 경우)가 그렇습니다.
위의 경우 return 된 Page Object를 사용해서 navigating 하는 방법은 효율적입니다. 테스트 코드에 page navigation 에 대한 내장된 로직을 넣게 되니까요. 만약에 이 로직이 non-trivial 이라면 이렇게 코딩을 하면 나중에 유지보수상의 문제가 생길겁니다. 그러면 Page Object 로부터 얻는 잇점 대신 그로인해 생기는 단점이 더 클 수도 있습니다.

반응형