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

최근에 받은 트랙백

글 보관함

Selenium WebDriver - PageFactory

2013. 10. 20. 02:14 | Posted by 솔웅


The PageFactory



PageObject 패턴을 지원하기 위해 Webdriver가 지원하는 라이브러리에는 factory 클래스가 포함돼 있습니다.



A Simple Example


PageFactory를 사용하기 위해 우선 WebElements나 List<WebElement>인 PageObject의 필드들을 정의해야 합니다.


예제를 보겠습니다.




package org.openqa.selenium.example;

import org.openqa.selenium.WebElement;

public class GoogleSearchPage {
    // Here's the element
    private WebElement q;

    public void searchFor(String text) {
        // And here we use it. Note that it looks like we've
        // not properly instantiated it yet....
        q.sendKeys(text);
        q.submit();
    }
}

이 코드가 제대로 작동되도록 하려면 q field를 제대로 초기화 시켜줘야 합니다.
여기서 우리는 PageObject를 초기화 해 줄 필요가 있습니다.

package org.openqa.selenium.example;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.support.PageFactory;

public class UsingGoogleSearchPage {
    public static void main(String[] args) {
        // Create a new instance of a driver
        WebDriver driver = new HtmlUnitDriver();

        // Navigate to the right place
        driver.get("http://www.google.com/");

        // Create a new instance of the search page class
        // and initialise any WebElement fields in it.
        GoogleSearchPage page = PageFactory.initElements(driver, GoogleSearchPage.class);

        // And now do the search.
        page.searchFor("Cheese");
    }
}


Explanation

The PageFactory relies on using sensible defaults: the name of the field in the Java class is assumed to be the "id" or "name" of the element on the HTML page. That is, in the example above, the line:


   q.sendKeys(text);



is equivalent to:


    driver.findElement(By.id("q")).sendKeys(text);



저기에서 사용된 driver 인스턴스는 PageFactory의 initElement 메소드에 전달된 그 인스턴스 입니다.


위 예제에서 우리는 PageFactory를 PageObject 인스턴스를 초기화 하는데 사용했습니다. 이렇게 함으로서 첫번째로 인수로 (public SomePage(WebDriver driver) {) WebDriver를 받는 생성자를 찾습니다. 만약에 그 생성자가 없으면 디폴트 생성자가 호출됩니다. 어떤 경우에는 PageObject는 WebDriver interface의 인스턴스말고도 다른것들을 필요로 합니다. 이미 생성된 객체의 element를 초기화하기 위해 PageFactory 가 사용 될 수도 있습니다.



ComplexPageObject page = new ComplexPageObject("expected title", driver);

// Note, we still need to pass in an instance of driver for the
// initialised elements to use
PageFactory.initElements(driver, page);



Making the Example Work Using Annotations



예제를 돌리면 PageFactory는 해당 페이지에서 이 클래스에 있는 WebElement의 필드 이름과 match 되는 element를 찾을 겁니다. 일단 ID 속성과 일치하는 element를 찾겠죠. 만약 찾지 못하면 PageFactory는 다시 뒤로 가서 그 name 속성의 value로 element를 찾을 겁니다.


이 코드가 작동 되더라도 Google 홈페이지의 소스코드를 잘 몰라서 field 의 이름이 q 라는 것을 모를겁니다. 다행히 우리는 annotation을 사용해서 이에 대해 알릴 수 있습니다..



package org.openqa.selenium.example;

import org.openqa.selenium.By;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.WebElement;

public class GoogleSearchPage {
    // The element is now looked up using the name attribute
    @FindBy(how = How.NAME, using = "q")
    private WebElement searchBox;

    public void searchFor(String text) {
        // We continue using the element just as before
        searchBox.sendKeys(text);
        searchBox.submit();
    }
}



한가지 걸리는 부분은 WebElement에 대해 메소드를 호출할 때마다 driver 가 현재 페이지에서 다시 그것을 찾을 거라는 겁니다. AJAX-heavy 어플리케이션에서 이것은 당연히 일어나는 일로 생각 될 수도 있습니다. 하지만 Google search 페이지에서는 그 element가 항상 거기에 있고 변하지 않을 거라는 것을 알고 있습니다. 그리고 우리는 해당 페이지이외의 페이지에서 작업하지 않을거라는 것도 알고 있구요. (같은 이름의 다른 element가 없을 거라는 것을 알고 있다는 얘기죠. 우리가 한번 찾아본 것은 그 element를 캐쉬에 넣어두면 더 유용할 겁니다.



package org.openqa.selenium.example;

import org.openqa.selenium.By;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.WebElement;

public class GoogleSearchPage {
    // The element is now looked up using the name attribute,
    // and we never look it up once it has been used the first time
    @FindBy(how = How.NAME, using = "q")
    @CacheLookup
    private WebElement searchBox;

    public void searchFor(String text) {
        // We continue using the element just as before
        searchBox.sendKeys(text);
        searchBox.submit();
    }
}


Reducing Verbosity



위의 예제는 아직도 좀 너무 복잡한거 같습니다. annotating을 약간 바꿔서 더 간단하게 만들겠습니다.



public class GoogleSearchPage {
  @FindBy(name = "q")
  private WebElement searchBox;

  // The rest of the class is unchanged.
}



Notes

    PageFactory를 사용하면 필드들이 초기화 됐다라고 가정하실 수 있습니다. 만약 PageFactory를 사용하지 않는다면 field들이 초기화 됐다고 가정하게 되면 NullPointerExceptions 가 발생할 겁니다.
    List<WebElement> 필드는 @FindBy 나 @FindBys annotation 이 있을 경우에 사용합니다. 디폴트 검색 strategy는 by id 나 by name 입니다. 한 페이지 내에 같은 아이디나 name을 가지는 엘리먼트들이 여러개 존재하는 경우는 드물기 때문에 WebElement 필드는 list로 사용하기 적합합니다.
    WebElements are evaluated lazily. 만약 PageObject에서 WebElement를 전혀 사용하지 않는다면 findElement를 호출하는 일은 없을 겁니다.
    The functionality works using dynamic proxies. 이 의미는 특정 subclass로서 WebElement를 기대해서는 안된다는 것입니다. 설사 여러분이 driver의 type을 알고 있더라도요. 예를 들어 HtmlUnitDriver를 사용하신다면 HtmlUnitWebElement의 인스턴스와 함께 WebElement 필드가 초기화 되기를 기대하시면 안 됩니다.

반응형

Comment

Selenium WebDriver - PageObjects

2013. 10. 19. 10:53 | Posted by 솔웅


PageObjects는 Selenium WebDriver 테스트에서 권장하는 디자인 패턴입니다.

반복되는 코드를 패턴화 해서 하나로 만들어 놓고 활용하는 방법입니다.

제가 충분히 이해를 못 했는지 원문이 해석하기 무척 힘드네요. 일단 Tutorial 을 한번 대강 해석해 놓고 나중에 소스를 좀 분석해 보겠습니다.


==================================

PageObjects 



Page Object 패턴은 객체들의 시리즈로서 여러분의 웹앱 화면들을 represent 합니다.


WebDriver



Updated Mar 31, 2013




Page Objects

웹앱 UI에서 어떤 테스트해야할 부분이 있습니다. Page Object는 이러한 테스트해야할 부분들을 테스트 코드내에서 한 객체로서 간단하게 다룹니다. 이것은 반복되는 코드를 줄이고 ,UI가 바뀌었을 때 한 부분만 고치면 되도록 만듭니다.


Implementation Notes

PageObject는 동시에 두가지 방향을 생각하게 할 수 있습니다. 우선 한 방향은 테스트를 하는 개발자에게 향하는 것입니다. 특정 페이지에 의해 제공되는 서비스가 됩니다. 두번째는 개발자로부터 나오는 방향입니다. HTML 페이지의 구조에 대한 깊은 이해가 있어야 합니다. Page Object는 페이지가 요구하는 그런 서비스의요구로서 생각됩니다. 예를 들어 웹베이스 이메일 시스템의 inbox를 생각해 봅시다. 여기서 제공하는 기능들은 편지를 쓰거나 어떤 이메일을 읽거나 inbox 내 이메일들의 리스트를 보여주는 겁니다. 이러한 것들이 테스트를 하는데 있어서 어떻게 implement 될까요.



우리는 개발자에게 implementation 하는것 보다 interaction 하는 그런 서비스들에 대해 좀 더 생각하도록 해야하기 때문에 PageObject는 WebDriver 인스턴스의 기본적인 부분들 같은 것들을 그렇게 드러내지 않습니다. 이것을 구현하기 위해 PageObject의 메소드들은 다른 PageObject를 return 해야 합니다. 이 의미는 우리 어플리케이션을 통해 유저의 사용경험들을 효과적으로 모델화 할 수 있다는 겁니다. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service, when it previously didn't do that) simply changing the appropriate method's signature will cause the tests to fail to compile. Put another way, we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.



이 접근법의 결과로는 성공적인 로그인과 성공적이지 않은 로그인 보두에 대한 모델링이 필요하다는 겁니다. 혹은 앱의 상황에 따라서 click 의 결과가 다르게 나올 수 있다는 것이구요. PageObject에 여러 메소드들을 갖는것은 일반적인 것입니다.



public class LoginPage {
    public HomePage loginAs(String username, String password) {
        // ... clever magic happens here
    }
   
    public LoginPage loginAsExpectingError(String username, String password) {
        //  ... failed login here, maybe because one or both of the username and password are wrong
    }
   
    public String getErrorMessage() {
        // So we can verify that the correct error is shown
    }
}



위의 코드를 보면 아주 중요한 부분이 있습니다. 이 테스트들은 PageObjects가 아닙니다. 페이지의 상태에 대한 assertion들을 만들어야 합니다. 예를 들어



public void testMessagesAreReadOrUnread() {
    Inbox inbox = new Inbox(driver);
    inbox.assertMessageWithSubjectIsUnread("I like cheese");
    inbox.assertMessageWithSubjectIsNotUnread("I'm not fond of tofu");
}



이 코드는 아래와 같이 재 작성해야 합니다.



public void testMessagesAreReadOrUnread() {
    Inbox inbox = new Inbox(driver);
    assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));
    assertFalse(inbox.isMessageWithSubjectIsUnread("I'm not fond of tofu"));
}




물론 모든 guideline에는 예외가 있습니다. 그중에 PageObjects에서 흔히 볼 수 있는 것이 우리가 PageObject를 초기화 할 때 맞는 페이지에서 WebDriver가 있는지에 대해 체크하는 것입니다. 이 작업은 아래 예제에서와 같이 처리하시면 됩니다.


마지막으로 PageObject는 모든 페이지를 represent 할 필요는 없습니다. PageObjects는 그 사이트나 페이지 내에서 여러번 반복되는 부분을 represent 하면 됩니다. 여기서 핵심은 특정 페이지의 HTML 구조에 대한 지식을 기반으로 여러분의 test suite 내에서 한 부분에서 이것을 만들어 두면 된다는 겁니다.


Summary

    The public methods represent the services that the page offers
    페이지에서 요구되는 서비스들을 represent 하는 public methods
    Try not to expose the internals of the page
    페이지의 내부적인 부분을 표현하려고 하지 않는다.
    Generally don't make assertions
    일반적으로 assertion들을 만들지 않는다.
    Methods return other PageObjects
    다른 PageObjects를 return 한다.
    Need not represent an entire page
    전체 페이지를 represent 할 필요는 없다.
    Different results for the same action are modelled as different methods
    같은 action에 대한 다른 결과들을 위해 다른 메소드들로 모델링 한다.




Example



public class LoginPage {
    private final WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;

        // Check that we're on the right page.
        if (!"Login".equals(driver.getTitle())) {
            // Alternatively, we could navigate to the login page, perhaps logging out first
            throw new IllegalStateException("This is not the login page");
        }
    }

    // The login page contains several HTML elements that will be represented as WebElements.
    // The locators for these elements should only be defined once.
        By usernameLocator = By.id("username");
        By passwordLocator = By.id("passwd");
        By loginButtonLocator = By.id("login");

    // The login page allows the user to type their username into the username field
    public LoginPage typeUsername(String username) {
        // This is the only place that "knows" how to enter a username
        driver.findElement(usernameLocator).sendKeys(username);

        // Return the current page object as this action doesn't navigate to a page represented by another PageObject
        return this;   
    }

    // The login page allows the user to type their password into the password field
    public LoginPage typePassword(String password) {
        // This is the only place that "knows" how to enter a password
        driver.findElement(passwordLocator).sendKeys(password);

        // Return the current page object as this action doesn't navigate to a page represented by another PageObject
        return this;   
    }

    // The login page allows the user to submit the login form
    public HomePage submitLogin() {
        // This is the only place that submits the login form and expects the destination to be the home page.
        // A seperate method should be created for the instance of clicking login whilst expecting a login failure.
        driver.findElement(loginButtonLocator).submit();

        // Return a new page object representing the destination. Should the login page ever
        // go somewhere else (for example, a legal disclaimer) then changing the method signature
        // for this method will mean that all tests that rely on this behaviour won't compile.
        return new HomePage(driver);   
    }

    // The login page allows the user to submit the login form knowing that an invalid username and / or password were entered
    public LoginPage submitLoginExpectingFailure() {
        // This is the only place that submits the login form and expects the destination to be the login page due to login failure.
        driver.findElement(loginButtonLocator).submit();

        // Return a new page object representing the destination. Should the user ever be navigated to the home page after submiting a login with credentials
        // expected to fail login, the script will fail when it attempts to instantiate the LoginPage PageObject.
        return new LoginPage(driver);  
    }

    // Conceptually, the login page offers the user the service of being able to "log into"
    // the application using a user name and password.
    public HomePage loginAs(String username, String password) {
        // The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.
        typeUsername(username);
        typePassword(password);
        return submitLogin();
    }
}


Support in WebDriver

이 패턴을 지원하는 패키지로 PageFactory 가 있습니다. 이것은 PageObjects에서 boiler-plate 코드를 동시에 remove 하는 것을 도와 줍니다.


=================================================


사실 이 글을 읽고는 무엇인지 확실히 이해를 잘 못하겠구요. 그나마 저 소스코드를 보니까 대강 알 수 있을 것 같습니다.


이 LoginPage 클래스에서는 우선 생성자에서 여기가 login 페이지가 맞는지 확인하고 해당 페이지가 아니면 예외를 발생 시키네요.

이 클래스는 로그인 페이지를 위한 클래스 입니다.


그리고 By type의 객체 세개를 만들었는데 각각 id로 유저명, 비밀번호 그리고 login 버튼을 찾는 객체들입니다.


첫번째 메소드는 typeUsername 인데요. 여기서는 LoginPage를 return 하네요.

PageObjects는 다른 PageObjects를 return 한다던데 이것을 말하나 봅니다.

그 안에는 by id 로 유저명을 찾아서 거기다가 전달 받은 파라미터를 type 해 넣습니다.


두번째 메소드인 typePassword도 똑 같습니다. 여기는 비밀번호를 쳐 넣는겁니다.


그 다음 메소드인 submitLogin 이 나오는데요. 

여기서는 HomePage를 return 하네요.

메소드 내에서는 login button을 클릭하는 일을 하구요.


id하고 비밀번호를 입력하고 login 버튼을 클릭하게 되겠죠.


그 다음 메소드는 이전 메소드와 완전히 똑 같습니다. 단지 이름이 submitLoginExpectingFailure() 인걸로 봐서 fail이 예상될 때 호출하는 메소드 인가 봅니다.


그 다음 loginAs() 메소드가 실제 실행할 때 호출하는 메소드인데요.

username과 password를 파라미터로 받아서 typeUsername()과 typePassword() 를 호출해서 아이디와 비밀번호를 타입하고 return submitLogin() 함으로서 로그인 버튼을 클릭하고 성공한 페이지를 return 하는 일을 합니다.

이렇게 하면 로그인 기능은 어디서든지 불러서 사용할 수 있겠네요.


그러면 이 부분에 대한 반복되는 코딩을 막을 수 있구요.


아이디, 비밀번호 이외에 다른 정보가 들어가는 걸로 바뀌거나 아이디에 대한 룰이 바뀌거나 하면 이 부분만 바꿔주면 되구요.


이 패턴을 지원하는 패키지가 PageFactory 라고 하니까 다음 글에서는 이걸 한번 배워봐야겠습니다.


반응형

Comment

Selenium WebDriver Tutorial 03

2013. 10. 18. 10:44 | Posted by 솔웅


이 글은 Selenium WebDriver 튜토리얼을 3번에 걸쳐 번역한 글 중 하나입니다.

원본은 여기에 있습니다.



Driver Specifics and Tradeoffs



Selenium-WebDriver’s Drivers



WebDriver는 작성되어야 할 테스트에 대한 key interface 이름입니다. 여기에는 몇개의 implementation들이 있습니다. 그것들을 살펴보겠습니다.



HtmlUnit Driver

이것이 현재 가장 빠르고 가장 가벼운 implemeatation 입니다. 이것은 HtmlUnit에 기초하고 있습니다. HtmlUnit은 GUI 가 없는 WebBrowser의 자바 베이스 implementation입니다. 자바 이외의 언어는 이 드라이버를 사용하기 위해 Selemium Server를 binding 해야 합니다.


Usage


WebDriver driver = new HtmlUnitDriver();


장점

    WebDriver를 가장 빨리 implementation 함
    pure Java solution으로 플랫폼 독립적이다.
    자바스크립트를 지원함


단점

    다른 브라우저의 자바스크립트 behaviour 를 Emulate 해야 한다.

   



JavaScript in the HtmlUnit Driver


주요 브라우저들은 HtmlUnit (Rhino)에 의해 사용되는 자바스크립트 엔진을 사용하지 않습니다. HtmlUnit을 사용하는 자바스크립트를 테스트 한다면 이 브라우저들에서는 그 결과가 다르게 나올 겁니다.


우리가 자바스크립트라고 말할 때 실제 이 의미는 자바스크립트와 DOM을 말하는 겁니다. DOM 이 W3C에 의해 정의 됐음에도 불구하고 각 브라우저들은 이 DOM의 implementation과 관련해서 자기들만의 방법을 사용하고 있습니다. 그래서 그에 따라 자바스크립트가 어떻게 작동하는지도 서로 다릅니다. HtmlUnit은 DOM을 implementation 하는 아주 확실한 방법입니다. 그리고 자바스크립트를 사용하기 위한 좋은 방법을 지원하고 있습니다. 하지만 다른 브라우저들도 그렇기는 합니다. W3C 표준과 여러 주요 브라우저들의 implementation들은 서로 다릅니다.


WebDriver와 관련해서 우리는 선택을 해야 합니다. HtmlUnit의 자바스크립트를 사용해서 팀원들이 실행할 때 생길 수 있는 위험성을 감수해야 할지 아니면 자바스크립트를 disable 해야 하는지요. 디폴트로는 HtmlUnit을 사용할 때 자바스크립트를 default로 함으로서 피해를 줄일수도 있겠죠. WebDriver와 HtmlUnit 모두를 release 하는데 있어 우리는 특정 부분에서 HtmlUnit의 디폴트로 자바스크립트를 enable 로 하기를 바랍니다.


Enabling JavaScript


그때까지 기다리기 힘드시면 자바스크립트를 enable 하도록 만드는것은 굉장히 쉽습니다.


HtmlUnitDriver driver = new HtmlUnitDriver(true);


이렇게 하면 HtmlUnit Driver에서 디폴트로 파이어폭스 3.6 버전의 자바스크립트를 emulate 합니다.



Firefox Driver

Firefox 플러그인을 사용해서 파이어폭스 브라우저를 사용할 수 있습니다. 사용되는 Firefox 프로파일은 Selenium WebDriver.xpi (플러그인)을 포함합니다. A few settings are also changed by default ((see the source to see which ones) ) Firefox Driver는 윈도우, 맥, 리눅스에서 실행하고 테스트할 수 있습니다.


Usage


WebDriver driver = new FirefoxDriver();


장점

    실제 브라우저에서 실행하고 자바스크립트를 지원함
    인터넷 익스플로러 Driver 보다 빠르다.

단점

    HtmlUnit Driver 보다 느리다.

   


Modifying the Firefox Profile


user agent string을 수정할 수도 있습니다. 그러려면 여러 유용한 extension들을 포함하고 있는 파이어폭스 프로파일을 trick out 해야 합니다. 이 프로파일을 obtain하는데는 두가지 방법이 있습니다. Firefox의 프로파일 매니저에 의해 프로파일이 생성됐다고 가정하고 아래 코드를 보겠습니다. (firefox -ProfileManager):


ProfilesIni allProfiles = new ProfilesIni();
FirefoxProfile profile = allProfiles.getProfile("WebDriver");
profile.setPreferences("foo.bar", 23);
WebDriver driver = new FirefoxDriver(profile);


프로파일이 Firefox로 register 되지 않았을 경우는 이렇게 합니다.


File profileDir = new File("path/to/top/level/of/profile");
FirefoxProfile profile = new FirefoxProfile(profileDir);
profile.addAdditionalPreferences(extraPrefs);
WebDriver driver = new FirefoxDriver(profile);


리눅스에서 Firefox에 native event들이 디폴트로 disable되어 있다면 다음과 같이 enable 되게 할 수 있습니다.


FirefoxProfile profile = new FirefoxProfile();
profile.setEnableNativeEvents(true);
WebDriver driver = new FirefoxDriver(profile);


Info


See the Firefox section in the wiki page for the most up to date info.


Internet Explorer Driver


이 driver는 .dll에 의해 콘트롤 됩니다. 이것은 Windows OS에서만 사용 가능합니다. Selenium 은 XP 의 버전 6,7,8 과 Windows7 상의 버전 9 에 맞게 만들었습니다.


Usage


WebDriver driver = new InternetExplorerDriver();


Pros

    실제 브라우저에서 실행되고 IE가 지원하는 자바스크립트를 지원한다.


Cons

    IE는 윈도우즈에서만 작동한다.
    비교적 느리다.
    대부분의 버전에서 native 하게 XPath를 지원하지 않는다. 다른 브라우저보다 느린 Sizzle이 자동적으로 inject 된다. 어떤 브라우저에서는 CSS selector와 비교할 때 더 느리다.
    버전 6,7에서는 CSS 가 native 적으로 지원하지 않는다. 대신 Sizzle이 inject 된다.
    IE 8,9에서 CSS selector는 native 이다. 하지만 그 브라우저에서는 CSS3를 완전히 지원하지 않는다.


Info

See the Internet Explorer section of the wiki page for the most up to date info. Please take special note of the Required Configuration section.



Chrome Driver


Chrome Driver는 Chromium project에 의해 유지되고 지원됩니다. WebDriver는 chromedriver binary를 통해서 Chrome과 함께 작동됩니다. (found on the chromium project’s download page). 이것을 사용하려면 chromedriver와 인스톨 된 chrome browser가 모두 있어야 합니다. chromedriver는 여러분 컴퓨터 내의 어딘가에 있어야 합니다. 그리고 그 경로를 세팅해서 WebDriver가 자동적으로 찾을 수 있도록 해야 합니다. Chrome browser는 chromedriver에 의해 인스톨된 경로를 자동으로 찾을 겁니다. 이런 것들은 환경변수로 overridden 할 수 있습니다. Please refer to the wiki for more information.


Usage


WebDriver driver = new ChromeDriver();



Pros

    실제 브라우저에서 동작되고 자바스크립트를 지원한다.
    Chrome이 Webkit-based 브라우저이기 때문에 Chrome Driver는 Safari에서 동작하는 것들에 대해서도 verify할 수 있습니다. Chrome은 V8 자바스크립트 엔진을 사용하고Safari는 Nitro 엔진을 사용합니다. 그러니까 JavaScript가 실행되는 것이 서로 다를 수도 있습니다.



Cons

    HtmlUnit Driver 보다 느리다.



Info


See our wiki for the most up to date info. More info can also be found on the downloads page



Getting running with Chrome Driver

Download the Chrome Driver executable and follow the other instructions on the wiki page



Opera Driver

See the Opera Driver wiki article in the Selenium Wiki for information on using the Opera Driver.

iPhone Driver

See the iPhone Driver wiki article in the Selenium Wiki for information on using the Mac iOS Driver.

Android Driver

See the Android Driver wiki article in the Selenium Wiki for information on using the Android Driver.




Alternative Back-Ends: Mixing WebDriver and RC Technologies



WebDriver-Backed Selenium-RC



자바버전의 WebDriver는 Selenium-RC API의 implementation을 제공합니다. 이 의미는 여러분이 Selenium-RC API에 있는 기능들을 WebDriver에서도 사용할 수 있다는 겁니다. 즉 이전 버전의 기능들도 모두 사용할 수 있다는 것이죠. 이미 Selenium-RC API를 사용한 테스트 suite들을 가지고 있는 분들이 WebDriver의 기능들을 사용해야 하는 분들에게 좋은 소식이죠. 이것을 Selenium-WebDriver로 migration을 쉽게 해 줍니다. 또한 두 API 모두를 한번에 사용할 수도 있습니다.


Selenium-WebDriver is used like this:


// You may use any WebDriver implementation. Firefox is used here as an example
WebDriver driver = new FirefoxDriver();

// A "base url", used by selenium to resolve relative URLs
 String baseUrl = "http://www.google.com";

// Create the Selenium implementation
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);

// Perform actions with selenium

selenium.open("http://www.google.com");
selenium.type("name=q", "cheese");
selenium.click("name=btnG");

// Get the underlying WebDriver implementation back. This will refer to the
// same WebDriver instance as the "driver" variable above.
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getWrappedDriver();

//Finally, close the browser. Call stop on the WebDriverBackedSelenium instance
//instead of calling driver.quit(). Otherwise, the JVM will continue running after
//the browser has been closed.
selenium.stop();


Pros

    WebDriver와 Selenium API를 함께 사용할 수 있다.
    Selenium RC API에서 WebDriver API로 migration 하는 간단한 방법을 제공한다.
    실행하기 위해 Selenium RC server를 필요로 하지 않는다.


Cons

    Does not implement every method
    모든 메소드를 implement 하지는 않는다.
    좀 더 advanced 한 Selenium 사용기능이 제대로 작동하지 않는다. (using “browserbot” or other built-in JavaScript methods from Selenium Core)
    어떤 메소드는 서로 다른 implementation으로 인해 느려질 수 있다.


   
Backing WebDriver with Selenium


WebDriver는 Selenium RC 보다 적은 브라우저들을 지원합니다. 그래서 Selenium RC 버전을 WebDriver API 버전으로 사용하려면 SeleneseCommandExecutor를 사용할 수 있습니다.



Safari는 이와 같은 방법으로 지원되는데요. 다음과 같이 코딩하면 됩니다. (be sure to disable pop-up blocking):


DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setBrowserName("safari");
CommandExecutor executor = new SeleneseCommandExecutor(new URL("http://localhost:4444/"), new URL("http://www.google.com/"), capabilities);
WebDriver driver = new RemoteWebDriver(executor, capabilities);


이렇게 접근하는 방법에는 중요한 몇가지 제한이 있습니다. findElements가 원하는대로 작동 안될 수도 있습니다. 또한 Selenium Core를 사용하기 때문에 자바스크립트 sandbox도 제한이 있습니다.


Running Standalone Selenium Server for use with RemoteDrivers


Selenium’s Download page에서 download selenium-server-standalone-<version>.jar 를 다운받으시고 옵션으로 IEDriverServer도 다운 받습니다. Chrome을 사용하려면 Google Code에서 다운 받으세요.


IEDriverServer와 chromedriver를 unpack 하고 이것을 $PATH / %PATH% 에 넣으세요. 그러면 추가적인 수정없이 IE와 Chrome 을 사용하실 수 있습니다.


Start the server on the command line with


java -jar <path_to>/selenium-server-standalone-<version>.jar


If you want to use native events functionality, indicate this on the command line with the option


-Dwebdriver.enable.native.events=1


For other command line options, execute


java -jar <path_to>/selenium-server-standalone-<version>.jar -help


In order to function properly, the following ports should be allowed incoming TCP connections: 4444, 7054-5 (or twice as many ports as the number of concurrent instances you plan to run). Under Windows, you may need to unblock the applications as well.



Additional Resources


WebDriver에 대해 좀 더 많은 것을 아시려면 WebDriver’s wiki를 보세요.


그리고 인터넷에서 Selenium-WebDriver’s drivers를 포함해서 Selenium과 관련된 여러 정보를 찾아보세요. Selenium과 관련한 여러 블로그와 포럼들이 있을 겁니다. 참고로 Selenium 사용자 그룹에도 정보가 아주 많습니다. http://groups.google.com/group/selenium-users



Next Steps.


이글은 WebDriver를 high level로 간단히 훑어 본 겁니다. 일단 Selenium-WebDriver API에 익숙해 지면 그 다음에는 어떻게 test suite들을 만드는지에 대해 궁금하실 겁니다. 요즈음 Selenium 전문가들이 접근하는 방법은 Page Factory를 사용해서 Page Object Design Pattern을 사용해서 테스트 코드를 디자인 하는 겁니다. Selenium-WebDriver는 자바와 C#에서 PageFactory 를 지원합니다. 이것은 next chapter에서  advanced topic을 다루는 글에서 다뤄집니다. 이 기술과 관련한 high-level description에 대해서는 Test Design Considerations chapter에서 다뤄 집니다. 이 두 글들은 여러분의 테스트 코드를 좀 더 유지보수하기 쉽도록 작성하는 방법을 알려 줍니다.

반응형

Comment


Selenium WebDriver 와 TestNG 를 같이 사용하는 방법을 정리하겠습니다. 그리고 xml을 이용해서 parallel 하게 같은 테스트를 여러 브라우저에서 같이 테스트 하는 방법도 알아보구요.


우선 실제 Test를 하는 클래스부터 봅니다.


public class WebDriverTest extends SelTestCase {
    @Test
    public void testWiki() {
        driver.get("http://www.wikipedia.org/");
        driver.findElement(By.id("searchInput")).sendKeys("Selenium Software");
        driver.findElement(By.name("go")).click();
        driver.findElement(By.cssSelector(".mw-search-results li:nth-of-type(1) a")).click();
        Assert.assertTrue(
                driver.findElement(
                        By.cssSelector("img[src='//upload.wikimedia.org/wikipedia/en/5/5c/Seleniumlogo.png']")).
                        isDisplayed());
        Reporter.log("My test Passed");
    }
}


이 WebDriverTest는 SelTestCase를 extends 했습니다. 이 SelTestCase는 나중에 보고 이 소스부터 분석하겠습니다.

@Test 는 annotation 인데요. jUnit 이랑 똑같습니다. 그런데 여기서는 TestNG를 사용할 거니까 TestNG를 import 해야 합니다.


import org.testng.annotations.Test;


다음은 testWiki()라는 테스트 메소드를 만듭니다.

여기서는 wikipedia.org 페이지를 열고 id 가 searchInput 인 element를 찾아서 거기에 Selenium Software 를 입력합니다. 아마 이 element는 textfield나 textarea 일 겁니다.

그 다음엔 name 이 go 인 엘리먼트를 click 합니다.

그 다음엔 cssSelector를 사용하는데요. class 가 mw-search-results 인것을 찾고 그 안에 li 인 것 중에 가장 첫번째 li에 있는 a 링크를 찾아서 그 링크를 클릭합니다.

그 다음에 테스트 문이 들어가는데요. 링크를 클릭해서 나온 페이지에 해당 이미지가 있으면 테스트가 Success 될 것이고 이 이미지가 없으면 fail 될 겁니다.

그 다음에는 TestNG에서 자동으로 생성해 주는 Report 에 log가 찍히도록 해 줍니다.


그런데 여기서 driver라는 객체가 있는데 이 객체를 선언해 주는 부분이 없습니다.

이 driver 객체는 상속받은 SelTestCase 클래스에서 선언해 주었을 겁니다.


public class SelTestCase {
    WebDriver driver;
   
    @BeforeMethod()
    @Parameters("browser")
    public void launchBrowser(String browser) {
        String path = System.getProperty("user.dir"); // current path of project

        if(browser.equalsIgnoreCase("FF")){
            driver = new FirefoxDriver();
        }else if(browser.equalsIgnoreCase("Chrome")){
            System.setProperty("webdriver.chrome.driver",path + "\\chromedrive\\chromedriver.exe");
            driver = new ChromeDriver();
        }else if (browser.equalsIgnoreCase("IE")) {
            System.setProperty("webdriver.ie.driver",path + "\\iedrive\\IEDriverServer.exe");
            driver = new InternetExplorerDriver();
        }
    }
   
    @AfterMethod
    public void closeBrowser() {
        driver.close();
        driver.quit();
    }
}

이 SelTestCase 클래스에서는 맨 먼저 WebDriver 를 초기화 시킵니다. 여기서 초기화 


그 다음에 @BeforeMethod() annotation이 있는데요. 이것은 테스트 메소드가 실행되기 전에 실행하라는 의미 입니다.

그러니까 WebDriverTest 클래스에 있는 testWiki() 라는 테스트 메소드가 시작되기 전에 이 메소드가 시작 됩니다.


그 다음에 있는 annotation은 파라미터로서 browser를 받겠다는 건데요. 이 파라미터는 다음에 볼 xml 파일에서 던져 줄 겁니다.


해당 메소드를 보면은요. launchBrowser() 라는 메소드인데요 스트링을 input 파라미터로 받습니다.

그 안을 보면 path라는 스트링에 이 프로젝트의 현재 위치를 대입합니다.


그리고 if 문이 나오는데요. input 파라미터가 FF 이면 FirefoxDriver() 를 driver 객체에 대입하고 Chrome인 경우는 ChromeDriver()를 그리고 IE인 경우에는 인터넷 익스플로러 드라이버를 drive 객체에 대입합니다.


그러니까 저 위에 있는 WebDriverTest 클래스의 testWiki() 테스트 메소드가 시작되기 전에 조건에 맞게 driver 객체를 세팅한 후 그 테스트 메소드가 실행될 겁니다.


다음에 나오는 건 @AfterMethod 가 있는 걸로 봐서 저 testWiki() 테스트 메소드가 실행되고 난 다음에 실행되는 메소드 입니다.

이름이 closeBrower() 이고 그 안에는 브라우저를 close하고 메모리로부터 driver 객체를 완전히 없애는 quit을 해주는 메소드 입니다.


이 두 클래스에서는 TestNG와 Selenium WebDriver를 같이 사용하고 있습니다.


여기에서 이 한개의 테스트를 여러 웹 브라우저에서 테스트할 수 있도록 하는 작업을 하겠습니다.

그러면 해당 프로젝트에 xml 파일을 만들어야 합니다.


testng.xml 이라는 파일을 아래와 같이 만듭니다.


<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Widipedia Test" verbose="3" parallel="methods">
    <test name="Wiki in FF">
    <parameter name="browser" value="FF"></parameter>
        <classes>
            <class name="WebDriverTest"/>
        </classes>
    </test>
   
    <test name="Wiki in Chrome">
    <parameter name="browser" value="Chrome"></parameter>
        <classes>
            <class name="WebDriverTest"/>
        </classes>
    </test>
    <!--
    <test name="Wiki in IE">
    <parameter name="browser" value="IE"></parameter>
        <classes>
            <class name="WebDriverTest"/>
        </classes>
    </test>   
     -->
</suite>

<suite> 태그를 써서 여러 테스트를 한개의 suite에 담겠다는 것을 알립니다.

그리고 <test> 태그 안에 각각의 테스트들을 정의 합니다.

첫번째는 <parameter> 태그안에 name 이 browser이고 value 는 FF 를 설정합니다.

이 것이 SelTestCase 클래스에 있는 launchBrowser()메소드에 전달될 파라미터 입니다.

그 다음에 <classes> 태그 안에는 name 에  WebDriverTest 를 넣습니다.

이 클래스를 run 하라는 겁니다.


그 다음에는 Chrome 과 IE 에 대한 <test> 태그들을 같은 방식으로 만듭니다.


여기서 IE는 주석처리를 했습니다.

제가 해 보니까 에러가 나더라구요.

혹시 이 IE는 왜 에러가 나는지 아시는 분은 좀 알려 주세요.


이 test suite를 실행하려면 Run-run configurations 를 선택합니다.




여기서 보시다시피 프로젝트를 선택하고 Suite를 선택한 다음에 아까 만들었던 xml 을 세팅합니다.


그러면 이 xml에서 정의된 대로 테스트가 여러 브라우저에서 실행될 겁니다.



반응형

Comment

  1. 즐거운 주말이 되세요.

Selenium WebDriver Tutorial 02

2013. 10. 17. 13:20 | Posted by 솔웅


Migrating from Selenium 1.0



Selenium 1.0을 사용해서 만든 test suit들을 가지고 계시다면 이것을 어떻게 Selenium 2.0으로 migrate 하는지에 대해 팁을 알려 드리겠습니다. Simon Stewart는 Selenium 2.0 의 lead developer 인데오 Selenium 1.0에서 migrating 하는 방법에 대해 글을 썼습니다. 아래 링크를 참조하세요.

Migrating From Selenium RC to Selenium WebDriver



Introducing the Selenium-WebDriver API by Example


WebDriver는 웹 어플리케이션 테스팅 자동화 툴입니다. 특정 기능이 디자인한대로 제대로 작동하는지를 점검하는 일을 하죠. 이 WebDriver는 Selenium-RC (1.0)API 보더 더 쉽게 접근할 수 있도록 발전시킨 API를 제공합니다. 이것을 통해서 여러분의 테스트들을 읽기 쉽고 유지관리하기 쉽게 도와 줍니다. WebDriver는 다른 테스트 플랫폼에 종속되지 않습니다. 그렇기 때문에 유닛테스팅이나 main 메소드를 통한 테스팅 모두에 사용될 수 있습니다. 이번 글에서는 WebDriver의 API를 소개하고 실제 사용하는 방법에 대해 알아보겠습니다. 아직 WebDriver가 설치되지 않았다면 셋업부터 시작하세요. 이래 링크를 따라가시면 관련 글이 있습니다.

Setting Up a Selenium-WebDriver Project.



일단 프로젝트가 셋업 됐다면 일반 라이브러리를 사용하듯이 WebDriver르르 사용하실 수 있습니다.


Note: additional steps are required to use Chrome Driver, Opera Driver, Android Driver and iPhone Driver


이제 코딩할 준비가 다 됐는데요. 예제를 통해서 설명하겠습니다. 이 예제는 구글을 통해서 Cheese라는 단어로 검색을 하는 겁니다. 검색 후 다음 페이지의 title을 콘솔에 찍어 보겠습니다.



package org.openqa.selenium.example;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

public class Selenium2Example  {
    public static void main(String[] args) {
        // Create a new instance of the Firefox driver
        // Notice that the remainder of the code relies on the interface,
        // not the implementation.
        WebDriver driver = new FirefoxDriver();

        // And now use this to visit Google
        driver.get("http://www.google.com");
        // Alternatively the same thing can be done like this
        // driver.navigate().to("http://www.google.com");

        // Find the text input element by its name
        WebElement element = driver.findElement(By.name("q"));

        // Enter something to search for
        element.sendKeys("Cheese!");

        // Now submit the form. WebDriver will find the form for us from the element
        element.submit();

        // Check the title of the page
        System.out.println("Page title is: " + driver.getTitle());
       
        // Google's search is rendered dynamically with JavaScript.
        // Wait for the page to load, timeout after 10 seconds
        (new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver d) {
                return d.getTitle().toLowerCase().startsWith("cheese!");
            }
        });

        // Should see: "cheese! - Google Search"
        System.out.println("Page title is: " + driver.getTitle());
       
        //Close the browser
        driver.quit();
    }
}



다음 글에서는 WebDriver에 대해 좀 더 많은 것을 배울 겁니다. 예를 들어 브라우저 히스토리에서 navigating forward, backward 하는 방법이나 frame과 window를 사용해 웹 사이트를 테스트하는 방법같은 것들이요.


Selenium-WebDriver API Commands and Operations



Fetching a Page



WebDriver로 할 첫번째 일은 page를 navigate 하는 겁니다. 일반적으로 get() 메소드를 호출함으로서 이 작업을 할 수 있습니다.


driver.get("http://www.google.com");


OS/Browser combination을 포함한 여러 조건에 따라 WebDriver는 페이지를 로드하는 동안 기다리거나 기다리지 않을 수도 있습니다. 특정 환경에서 WebDriver는 페이지가 finish되기 전에 혹은 시작되거나 loading되기 전에  control을 return 할 겁니다. 제대로 된 테스트를 하기 위해 명시적으로 혹은 암시적으로 페이지내에 있는 element들을 기다리는 시간이 필요합니다.



Locating UI Elements (WebElements)


WebDriver에 있는 element들은 WebDriver 인스턴스나 WebElement 에서 처리할 수 있습니다. 이 element를 찾는 명령어들이 있는데요. 이 Find Elements 메소드를 사용하면 우선 WebElement를 return 합니다. 그렇지 않으면 exception이 발생합니다. 그 다음에 WebElements의 리스트가 return 되구요. 이 query 와 DOM element가 맞지 않으면 empty 리스트가 return 될 수 있습니다.


이 Find 메소드는 By라고 하는 query 객체를 사용합니다.



By ID

이것은 element를 찾는데 가장 흔히 사용됩니다. UI를 개발하면서 한 페이지 내에 unique 하지 않은 id가 있을 수 있습니다. 혹은 자동으로 생성된 id가 있을 수 있구요. 두 경우 모두 피하셔야 합니다. id보다 html element에 있는 class  가 자동 생성되도록 하면 좋습니다.

Example of how to find an element that looks like this:


<div id="coolestWidgetEvah">...</div>


WebElement element = driver.findElement(By.id("coolestWidgetEvah"));



By Class Name


이 경우 Class 는 DOM element의 attribute를 참조합니다. 실제 작업을 하다 보면 같은 클래스 이름을 가지고 있는 많은 DOM element들이 있게 됩니다. 그러니까 이 경우 리스트를 사용해서 여러 element를 담도록 할 수 있습니다.


Example of how to find an element that looks like this:


<div class="cheese"><span>Cheddar</span></div><div class="cheese"><span>Gouda</span></div>


List<WebElement> cheeses = driver.findElements(By.className("cheese"));



By Tag Name



The DOM Tag Name of the element.

Example of how to find an element that looks like this:


<iframe src="..."></iframe>


WebElement frame = driver.findElement(By.tagName("iframe"));



By Name



Find the input element with matching name attribute.

Example of how to find an element that looks like this:


<input name="cheese" type="text"/>


WebElement cheese = driver.findElement(By.name("cheese"));



By Link Text


Find the link element with matching visible text.

Example of how to find an element that looks like this:


<a href="http://www.google.com/search?q=cheese">cheese</a>>


WebElement cheese = driver.findElement(By.linkText("cheese"));



By Partial Link Text


Find the link element with partial matching visible text.

Example of how to find an element that looks like this:


<a href="http://www.google.com/search?q=cheese">search for cheese</a>>


WebElement cheese = driver.findElement(By.partialLinkText("cheese"));



By CSS


Like the name implies it is a locator strategy by css.
대개 Native 브라우저는 디폴트로 이것을 사용합니다.
그러니까 일반적으로 사용되는 css selector들에 대한 w3c css selectors <http://www.w3.org/TR/CSS/#selectors> 를 참조하세요.
브라우저가 css query에 대한 native support를 하지 않으면 Sizzle이 사용됩니다. IE 6,7 그리고 파이어폭스 3.0 은 css query engine으로서 Sizzle을 사용합니다.


모든 브라우저가 똑같이 생성되는 것은 아닙니다. 어떤 css는 어떤 버전에서는 작동을 하지만 다른 버전에서는 작동을 안 할 수도 있습니다.


Example of to find the cheese below:


<div id="food"><span class="dairy">milk</span><span class="dairy aged">cheese</span></div>


WebElement cheese = driver.findElement(By.cssSelector("#food span.dairy.aged"));



By XPATH


WebDriver는 브라우저의 native XPath를 사용합니다. 이 native XPath 를 지원하지 않는 브라우저에 대해 우리는 나름대로의 implementation을 제공합니다. 다양한 xpath 엔진의 차이점으로 인해 기대했던 것과는 다른 결과가 나올 수 있습니다.

<table>

This is a little abstract, so for the following piece of HTML:

<input type="text" name="example" />
<INPUT type="text" name="other" />

List<WebElement> inputs = driver.findElements(By.xpath("//input"));

The following number of matches will be found

Driver Tag and Attribute Name Attribute Values Native XPath Support
HtmlUnit Driver Lower-cased As they appear in the HTML Yes
Internet Explorer Driver Lower-cased As they appear in the HTML No
Firefox Driver Case insensitive As they appear in the HTML Yes


This is a little abstract, so for the following piece of HTML:

<input type="text" name="example" />
<INPUT type="text" name="other" />

List<WebElement> inputs = driver.findElements(By.xpath("//input"));


The following number of matches will be found

XPath expression HtmlUnit Driver Firefox Driver Internet Explorer Driver
//input 1 (“example”) 2 2
//INPUT 0 2 0



어떤 HTML element들은 attribute에 대해 디폴트값을 사용한다면 명시적으로 정의할 필요가 없는것들도 있습니다. 예를 들어 input tag같은 경우 디폴트가 text 이기 때문에 이 경우 type attribute를 굳이 넣을 필요가 없습니다.  이 경우 WebDriver의 xpath를 사용한다면 원하는 결과가 안 나올 수도 있습니다.


Using JavaScript


element를 찾기 위해 자바스크립트를 실행할 수도 있습니다.

Simple example on a page that has jQuery loaded:


WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript("return $('.cheese')[0]");


Finding all the input elements to the every label on a page:


List<WebElement> labels = driver.findElements(By.tagName("label"));
List<WebElement> inputs = (List<WebElement>) ((JavascriptExecutor)driver).executeScript(
    "var labels = arguments[0], inputs = []; for (var i=0; i < labels.length; i++){" +
    "inputs.push(document.getElementById(labels[i].getAttribute('for'))); } return inputs;", labels);



User Input - Filling In Forms


textarea나 text field에 어떻게 text를 넣는지에 대해서는 이미 보았습니다. 그런데 다른 element들에는 어떻게 할까요. checkbox 같은 경우는 toggle을 할 수 있고 Opthion tag 같은 경우 click을 할 수 있습니다.


WebElement select = driver.findElement(By.tagName("select"));
List<WebElement> allOptions = select.findElements(By.tagName("option"));
for (WebElement option : allOptions) {
    System.out.println(String.format("Value is: %s", option.getAttribute("value")));
    option.click();
}


이렇게 하면 페이지 내의 첫번째 SELECT element를 찾을 겁니다. 그리고 각 OPTION들을 찾을 거구요. 그 다음에 그 옵션들을 출력할 겁니다. 그런데 이 방법은 그렇게 효율적인 방법이라고 할 수 없습니다. 이럴 경우는 아래와 같이 사용하시면 좀 더 유용하게 사용하실 겁니다.


Select select = new Select(driver.findElement(By.tagName("select")));
select.deselectAll();
select.selectByVisibleText("Edam");


이 경우 첫번째 SELECT의 모든 OPTION들의 선택을 해제하고 Edam이라는 OPTION만 선택할 겁니다.


form을 다 채워 넣으면 이 form 을 submit 해야 합니다. 이 일을 하려면 submit 버튼을 찾아서 이 버튼을 클릭하면 됩니다.


driver.findElement(By.id("submit")).click();


각 element들에 대해 WebDriver는 간편한 submit 메소드 기능을 제공합니다. form 인의 한 element에서 이것을 call 하면 WebDriver는 form이 감싸고 있는 부분을 DOM 에서 찾고 거기에 대해 submit 을 호출합니다. 이 element가 form 안에 있지 않다면 NoSuchElementException이 던져 집니다.


element.submit();



Moving Between Windows and Frames


어떤 웹 어플리케이션은 많은 프레임이나 윈도우들을 갖고 있습니다. WebDriver는 switchTo 메소드를 사용해서 이 프레임이나 윈도우를 이동할 수 있습니다.


driver.switchTo().window("windowName");


이렇게 하면 특정 윈도우 내에서만 작업하게 됩니다. 그런데 이 window의 이름은 어떻게 알까요? 자바스크립트나 이것을 open 한 링크를 보세요.


<a href="somewhere.html" target="windowName">Click here to open a new window</a>


또한 “switchTo().window()” method에 window handle을 전달 할 수도 있습니다. 이 작업은 아래처럼 모든 윈도우에 적용할 수도 있습니다.


for (String handle : driver.getWindowHandles()) {
    driver.switchTo().window(handle);
}


frame간에도 이동할 수 있는데요. (iframe도 포함)


driver.switchTo().frame("frameName");


dot(.)으로 구분해서 하위 프레임에 접근할 수도 있습니다. 물론 index를 사용해서 해당 프레임에 접근할 수도 있구요.


driver.switchTo().frame("frameName.0.child");


이렇게 하면 “frameName” 이라는 프레임의 첫번째 하위 프레임 내의 child라는 프레임으로 접근할 겁니다. All frames are evaluated as if from *top*.



Popup Dialogs


Selenium 2.0 beta 1 부터 popup dialog box를 지원하기 시작했습니다. popup을 뛰우면 아래와 같이 alert()을 사용해서 이 팝업에 접근할 수 있습니다.


Alert alert = driver.switchTo().alert();


이렇게 하면 현재 open 된 alert 객체를 return 합니다. 이 객체를 가지고 accept, dismiss 나 해당 contents를 읽고 prompt에 type 하는 작업등을 할 수 있습니다. 이 인터페이스는 alerts, confirms, prompts 에 모두 똑같이 사용됩니다. Refer to the JavaDocs or RubyDocs for more information.


Navigation: History and Location


이전에 get() 메소드를 사용해서 페이지를 navigating 해 봤었습니다. ( driver.get("http://www.example.com")).  to() 메소드를 사용할 수도 있습니다.


driver.navigate().to("http://www.example.com");


navigate().to() 와 get()은 같은 일을 합니다.

이 navigate 인터페이스는 backward와 forward도 지원합니다.


driver.navigate().forward();
driver.navigate().back();



Cookies


이제 쿠키를 어떻게 사용하는지에 대해서도 살펴 보겠습니다. 우선 쿠키가 사용될 도메인에 있어야 합니다.



// Go to the correct domain
driver.get("http://www.example.com");

// Now set the cookie. This one's valid for the entire domain
Cookie cookie = new Cookie("key", "value");
driver.manage().addCookie(cookie);

// And now output all the available cookies for the current URL
Set<Cookie> allCookies = driver.manage().getCookies();
for (Cookie loadedCookie : allCookies) {
    System.out.println(String.format("%s -> %s", loadedCookie.getName(), loadedCookie.getValue()));
}

// You can delete cookies in 3 ways
// By name
driver.manage().deleteCookieNamed("CookieName");
// By Cookie
driver.manage().deleteCookie(loadedCookie);
// Or all of them
driver.manage().deleteAllCookies();



Changing the User Agent


파이어폭스에서는 이 User Agent를 바꾸는 작업이 쉽습니다.


FirefoxProfile profile = new FirefoxProfile();
profile.addAdditionalPreference("general.useragent.override", "some UA string");
WebDriver driver = new FirefoxDriver(profile);



Drag And Drop

아래에 drag and drop을 시행할 수 있는 Actions 클래스에 대한 에제가 있습니다.


WebElement element = driver.findElement(By.name("source"));
WebElement target = driver.findElement(By.name("target"));

(new Actions(driver)).dragAndDrop(element, target).perform();



반응형

Comment

Selenium WebDriver Tutorial 01

2013. 10. 17. 01:25 | Posted by 솔웅


Selenium WebDriver

NOTE: We’re currently working on documenting these sections. We believe the information here is accurate, however be aware we are also still working on this chapter. Additional information will be provided as we go which should make this chapter more solid.



Introducing WebDriver



Selenium 2.0 의 새 기능중 중요한 부분은 WebDriver API 를 통합했다는 겁니다. WebDriver는 Selenium-RC API 의 한계를 극복하기 위한 기능들이 추가 된 것으로 프로그래밍을 좀 더 간단하고 간결하게 할 수 있도록 도와 줍니다. Selenium-WebDriver는 페이지가 reload 되지 않고도 페이지의 element들이 바뀌는 dynamic web page를 좀 더 제대로 지원하기 위해 만들었습니다. WebDriver의 목표는 현재 Web-App의 문제점들을 제대로 해결하기 위해 만들어진 잘 디자인된 객체 지향 API 입니다.



How Does WebDriver ‘Drive’ the Browser Compared to Selenium-RC?



Selenium-WebDriver는 자동화를 위해 각 브라우저 고유의 기능들을 지원함으로서 브라우저에 직접 호출하는 기능을 지원합니다. 어떻게 이렇게 직접 호출을 할 수 있고 어떤 기능들을 지원하느냐는 여러분이 사용하는 브라우저에 따라 다릅니다. 각 browser driver에 대한 정보는 나중에 살펴 보겠습니다.



Selenium-RC에 익숙하신 분들에게는 이 부분이 여러분이 사용하시던 부분과 좀 다를 겁니다. Selenium-RC는 각 브라우저에 대해 같은 방법으로 작독했습니다. 브라우저가 로드 되면 그 브라우저에 자바스크립트를 inject 하고 그 브라우저 안에서 AUT를 drive 하기 위해 그 자바스크립트를 사용합니다. WebDriver는 이와 같이 작동하지 않습니다. WebDriver는 automation을 위해 지원하는 브라우저의 고유 기능을 direct 하게 사용합니다.


WebDriver and the Selenium-Server



이 Selenium-WebDriver를 어떻게 사용할 것인가에 따라 Selenium Server가 필요할 수도 있고 그렇지 않을 수도 있습니다. 만약 WebDriver API 만을 사용할 거라면 Selenium-Server는 필요하지 않습니다. 만약 여러분의 브라우저와 테스트들이 같은 machine 에서 작동하고 여러분의 테스트가 WebDriver API만을 사용한다면 Selenium-Server가 필요하지 않습니다. WebDriver가 곧바로 그 브라우저를 실행시킬 겁니다.



Selenium-WebDriver와 함께 Selenium-Server를 사용하는데는 몇가지 이유가 있습니다.

       

- 여러분의 tests를 여러 machine들이나 virtual machines(VMs)에서 사용하기 위해 Selenium-Grid를 사용하는 경우.
      

- 여러분의 machine에 있지 않는 브라우저 버전을 갖고 있는 다른 machine에 remote로 접근해야 할 경우.
       

- Java bindings (Python,C#,Ruby 같은) 을 사용하지 않고 HtmlUnit Driver를 사용 할 경우.



Setting Up a Selenium-WebDriver Project



Selenium 을 인스톨한다는 의미는 development에 project를 셋업한다는 얘기입니다. 그렇게 되면 Selenium을 사용해서 프로그래밍 할 수 있게 되는거죠. 이것을 프로그래밍 언오와 개발환경에 따라 어떻게 할까요.





JAVA



Selenium 2.0 Java 프로젝트를 셋업하는 가장 쉬운 방법은 Maven을 이용하는 겁니다. Maven 은 java binding들 (Selenium 2.0 java client library)와 모든 dependency들을 다운로드 하고 프로젝트를 생성할 겁니다. 메이븐의 pom.xml (project configuration) 파일을 사용해서 이러한 일을 하시면 됩니다. 이 작업이 완료 되면 여러분은 maven 프로젝트를 여러분이 사용하시는 IDE (IntelliJ IDEA 나 이클립스)에 import 하실 수 있습니다.



첫번째로 Selenium project 파일들이 들어갈 폴더를 생성합니다. Maven을 사용하려면 pom.xml 파일이 필요합니다. 이 파일은 텍스트 에디터로 만들 수 있습니다. 이 pom.xml 파일이나 메이븐에 대한 자세한 부분은 다루지 않겠습니다. 아마 pom.xml은 아래와 같을 겁니다. 여러분 프로젝트를 위해 만든 폴더에 이 파일을 생성해 넣으세요.



<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>MySel20Proj</groupId>
        <artifactId>MySel20Proj</artifactId>
        <version>1.0</version>
        <dependencies>
            <dependency>
                <groupId>org.seleniumhq.selenium</groupId>
                <artifactId>selenium-java</artifactId>
                <version>2.35.0</version>
            </dependency>
            <dependency>
                <groupId>com.opera</groupId>
                <artifactId>operadriver</artifactId>
            </dependency>
        </dependencies>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.opera</groupId>
                    <artifactId>operadriver</artifactId>
                    <version>1.5</version>
                    <exclusions>
                        <exclusion>
                            <groupId>org.seleniumhq.selenium</groupId>
                            <artifactId>selenium-remote-driver</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
            </dependencies>
        </dependencyManagement>
</project>



이 때 최신 버전을 사용하세요. 위 코드 내의 버전들은이 글을 쓸 당시의 최종 버전들입니다. Maven download page를 체크하셔서 위의 코드 중 버전이 바뀐 경우 바꿔주세요.



이제 command-line에서 cd 로 해당 프로젝트 디렉토리로 가셔서 아래처럼 maven을 run 해 주세요.



mvn clean install



이렇게 하면 Selenium과 다른 dependency들을 다운받아 프로젝트에 추가할 겁니다.



마지막으로 이 프로젝트를 개발환경에 import 하시면 됩니다. 이 방법을 자세히 아시려면 아래 링크를 따라 가서 참고하시면 도움이 될 겁니다.



Importing a maven project into IntelliJ IDEA. Importing a maven project into Eclipse.



C#



As of Selenium 2.2.0, the C# bindings are distributed as a set of signed dlls along with other dependency dlls. Prior to 2.2.0, all Selenium dll’s were unsigned. To include Selenium in your project, simply download the latest selenium-dotnet zip file from https://code.google.com/p/selenium/downloads/list. If you are using Windows Vista or above, you should unblock the zip file before unzipping it: Right click on the zip file, click “Properties”, click “Unblock” and click “OK”.



Unzip the contents of the zip file, and add a reference to each of the unzipped dlls to your project in Visual Studio (or your IDE of choice).



Official NuGet Packages: RC WebDriver WebDriverBackedSelenium Support


Python



If you are using Python for test automation then you probably are already familiar with developing in Python. To add Selenium to your Python environment run the following command from a command-line.



pip install selenium



Pip requires pip to be installed, pip also has a dependency on setuptools.



Teaching Python development itself is beyond the scope of this document, however there are many resources on Python and likely developers in your organization can help you get up to speed.
Ruby



If you are using Ruby for test automation then you probably are already familiar with developing in Ruby. To add Selenium to your Ruby environment run the following command from a command-line.



gem install selenium-webdriver



Teaching Ruby development itself is beyond the scope of this document, however there are many resources on Ruby and likely developers in your organization can help you get up to speed.



Perl



Perl bindings are provided by a third party, please refer to any of their documentation on how to install / get started. There is one known Perl binding as of this writing.



PHP



PHP bindings are provided by a third party, please refer to any of their documentation on how to install / get started. There are three known bindings at this time: By Chibimagic By Lukasz Kolczynski and By the Facebook

반응형

Comment


오늘은 Selenium WebDriver를 이용한 예제를 하나 공부했습니다.


클래스를 실행 시키면 Firefox 브라우저를 켜서 gmail로 가고 아이디 입력과 비밀번호 입력 그리고 Log in 버튼을 누르는 것까지 실행하는 예제입니다.


import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class WebDriver_Ex {
    public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        driver.get("http://gmail.com");
//        WebElement username = driver.findElement(By.id("Email"));
        WebElement username = driver.findElement(By.xpath("//*[@id=\"Email\"]"));
        username.sendKeys("아이디");
        WebElement password  = driver.findElement(By.id("Passwd"));
        password.sendKeys("비밀번호");
       
        WebElement signInBtn = driver.findElement(By.id("signIn"));
        signInBtn.click();
    }
}



이 소스를 실행시키면 Firefox를 실행시키고 사용자 이름과 비밀번호를 주어진 값으로 채워 넣습니다.

그리고 로그인 버튼을 클릭하는 이벤트를 발생시켜서 gmail로 로그인을 합니다.


소스를 보면요.

먼저 WebDriver 인터페이스에 있는 FirefoxDriver()의 객체를 만듭니다.

다음에 get() 메소드를 사용해서 gmail 로 접속을 합니다.

여기까지 하면 파이어폭스 브라우저에 gmail.com 페이지가 뜹니다.


그 다음에는 gmail 페이지의 태그를 알아야 하는데요. 사용자 이름을 넣는 텍스트필드에 값을 넣어야 하는데 이때 사용할 수 있는 방법이 id로 하는 방법과 xpath 로 하는 방법이 있습니다.


이 페이지의 소스를 보려면 firebug 플러그인을 firefox 브라우저에 인스톨해서 사용하시면 편합니다.

xpath를 아시려면 firepath 를 인스톨 하시면 되구요.


자세한 방법은 검색하셔서 관련 글을 보시면 됩니다. 관련된 글이 많이 있을 겁니다.


이 Firebug를 통해서 보면 gmail 의 로그인 페이지에서 아이디를 넣는 텍스트 필드의 id 가 Email 인 것을 알 수 있습니다.

여기까지 알면 WebElement 를 사용해서 해당 텍스트 필드의 객체를 생성합니다.


WebElement username = driver.findElement(By.id("Email"));


혹은 Firepath 를 사용해서 xpath 를 알 수도 있습니다.

xpath 에는 절대경로(Absolute xpath,complete xpath)와 상대경로(partial xpath) 가 있는데요.

여기서는 상대경로를 사용합니다.

WebElement username = driver.findElement(By.xpath("//*[@id=\"Email\"]"));


이렇게 하면 아이디를 넣는 텍스트 필드의 WebElement 객체를 만들었습니다.


이러면 이 엘리먼트를 마음대로 다룰 수가 있게 됩니다.


아이디를 넣어야 하니까 이럴때눈 sendKeys() 메소드를 사용하시면 됩니다.

비밀번호두 마찬가지로 진행합니다.

그리고 로그인 버튼도 WebElement 객체를 만들어서 click() 메소드를 사용해서 클릭하도록 합니다.


이제 이 소스를 실행하면 gmail로 가서 아이디와 비밀번호를 입력하고 로그인 버튼을 눌러서 접속하는것까지 실행합니다.


Selenium 은 테스팅 툴입니다.


여기서는 그 다음페이지의 title을 받아서 원래 설계된 페이지로 제대로 왔는지 안 왔는지 여부를 테스트 할 수 있겠네요.


일단 오늘은 Selenium 을 사용해서 웹페이지에 있는 WebElement들을 control 하는 방법을 정리했습니다.


반응형

Comment


Maven Information


Maven을 사용하신다면 아래에 central Maven repository에서 Maven artifacts를 보실 수 있습니다.

 http://repo1.maven.org/maven2/org/seleniumhq/selenium/

DefaultSelenium이나 Maven 프로젝트의 WebDrever 중 하나를 사용하시려면 pom.xml에 아래 dependency를 추가하세요.

   

<dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>2.35.0</version>
    </dependency> 



Note: 2.0,rc3 이전 버전은 이 artifact 이름이 selenium-remote-control입니다.

다른 Maven artifacts를 보시려면 diagram을 보세요. Selenium Maven artifacts와 그 artifacts의 주요한 클래스들과 인터페이스들을 보실 수 있습니다.






특정 WebDriver implementation만을 사용하시려면 (예를 들어 FirefoxDriver 만 사용한다든지), selenium-java artifact 를 사용하지 않으셔도 됩니다. 여기에는 많은 transitive dependency들이 있습니다. 이것을 사용하는 대신 간단히 아래와 같은 dependency를 추가하시면 됩니다.

   

<dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-firefox-driver</artifactId>
        <version>2.35.0</version>
    </dependency> 


DefaultSelenium이나 RemoteWebDriver implementation 을 사용한다면 Selenium server를 사용해야 합니다. Selenium Downloads page  에서 selenium-server-standalone.jar를 다운 받으세요. 그리고 여러분 프로젝트에 이 Selenium 서버를 embed 하시면 됩니다. pom.xml 파일에 아래 dependency를 추가해 주세요.
 
   

<dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-server</artifactId>
        <version>2.35.0</version>
    </dependency> 



이제 SeleniumServer 인스턴스를 생성하실 수 있습니다.

selenium-server artifact는 servlet-api-2.5 artifact에 대한 dependency를 가지고 있다는 것을 명심하세요. 여러분 프로젝트가 웹 어플리케이션 컨테이너 안에서 실행된다면 여러분은 이것을 exclude 하셔야 합니다.


Third Party Browser Drivers NOT SUPPORTED/DEVELOPED by seleniumhq


Opera Driver

   

<dependency>
        <groupId>com.opera</groupId>
        <artifactId>operadriver</artifactId>
        <version>1.5</version>
    </dependency> 




PhantomJSDriver (GhostDriver)

  

<dependency>
        <groupId>com.github.detro.ghostdriver</groupId>
        <artifactId>phantomjsdriver</artifactId>
        <version>1.0.4</version>
    </dependency> 
 



반응형

Comment


Selenium WebDriver 관련 공부 하고 있습니다.

Youtube 에서 관련 Tutorial 찾아서 공부한 내용 정리합니다.


이 Tutorial 을 올린 애는 Ashish Thakur 로 홈페이지는 www.qtpselenium.com 입니다.




WebDriver 는 RC 의 확장된 버전입니다.

Selenium WebDriver는 Selenium 2 라고도 하는데 이걸로 요즘 나오는 모바일에 있는 웹브라우저용으로 테스트 케이스를 만들 수 있습니다.


우선 설치하는 방법은 아래와 같습니다.


1. Java를 인스톨 한다.
2. 이클립스 IDE for Java EE developers (Indigo Package) 를 다운 받는다.
3. Eclips 를 Run 한다. (Java 가 인스톨 돼 있어야 함)
   64bit일 경우 jdk 를 다운 받는다. (32bit면 그냥 JRE만 다운 받아도 될 것임)
4. Workspace 를 설정한다.
5. File-New-Project-Java-Java Project
   -> Project Name -> Finish
6. src right click -> New -> Class : 클래스 파일을 하나 만든다.

* Selenium 을 하려면 Java에 대해 알아야 한다.
* http://selenium.googlecode.com/git/docs/api/java/index.html 로 가면 Selenium에 대한 JavaDoc이 나옴

7. http://www.seleniumhq.org/download/ 로 가서 Selenium 을 다운로드 받는다. (Java 버전으로)
8. Project - Properties - Java Build Path - Libraries Tab - Add External Jars - selenium-lib 에 있는 모든  jar파일과 selenium-java-2.35.0.jar,selenium-java-2.35.0-srcs 들을 include 한다.


설치는 이렇게 하시면 됩니다.


그러면 FireFox, Chrome 그리고 IE 웹 브라우저용 WebDriver를 사용하는 예제를 보겠습니다.


import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public class Browsers {

    public static void main(String[] args) {
        FirefoxDriver d1 = new FirefoxDriver();
        d1.get("http://gosolkit.com");
       
        String path = System.getProperty("user.dir"); // current path of project
        System.setProperty("webdriver.chrome.driver",path + "\\chromedrive\\chromedriver.exe");
        ChromeDriver d2 = new ChromeDriver();
        d2.get("http://coronasdk.tistory.com");
       
        System.setProperty("webdriver.ie.driver",path + "\\iedrive\\IEDriverServer.exe");
        InternetExplorerDriver d3 = new InternetExplorerDriver();
        d3.get("http://www.qtpselenium.com");
       
        String title = d1.getTitle();
        System.out.println(title);
    }

}


이 클래스가 있는 project에서는 selenium 관련 jar 파일들이 모두 include 돼 있어야 합니다.


우선 첫번째로 Firefox를 사용하는 방법은요 그냥 FirefoxDriver() 객체를 하나 만들어서 사용하면 됩니다.

위 예제에서는 제 개인 싸이트를 get 했습니다.


두번째로 Chrome 을 사용할 때는 chromedriver.exe 를 설치 해야 됩니다.

다운 받는 장소는 http://www.seleniumhq.org/download/ 로 가셔서 찾아보시면 링크가 걸려 있을 겁니다. 


잘 못 찾겠으면 http://code.google.com/p/chromedriver/ 로 가셔서 다운 받으시면 됩니다.


다운 받으신 후 해당 프로젝트에 chromedriver 폴더를 만들고 그 안에 chromedriver.exe 파일을 복사해 넣습니다.



그리고 사용법은 webdriver.chrome.driver 를 사용해서 해당 exe 파일이 있는 경로가 있는 프로퍼티를 세팅해야 합니다.

여기서 현재 작업하고 있는 경로를 알 수 있는 System.getProperty("user.dir"); 를 사용하시면 좀 더 편하게 설정하실 수 있습니다.


이 프로퍼티를 설정하셨으면 ChromeDriver객체를 만드시면 됩니다.

위 예제에서는 get 을 사용해서 제 블로그를 이 크롬브라우저에 세팅했습니다.


그 다음은 IE 인데요. 이것도 Chrome 과 마찬가지로 http://www.seleniumhq.org/download/ 로 가셔서 해당 링크를 찾으세요. 

아니면 그냥 http://code.google.com/p/selenium/downloads/detail?name=IEDriverServer_x64_2.35.3.zip 로 가셔서 다운 받으셔도 됩니다. 


크롬 브라우저와 마찬가지로 인터넷 익스플로러도 webdriver.ie.driver 를 사용해서 프로퍼티를 세팅해 주세요.



그 다음에 InternetExplorerDriver 객체를 만드시면 됩니다.

위 예제에서는 제가 공부한 유튜브 강좌를 올린 Ashish 의 웹사이트를 get 해서 이 IE 브리우저에 세팅했습니다.


이렇게 객체를 세팅하고 나면 get() 으로 얻은 웹페이지에 있는 여러 element들의 정보를 가져오거나 event를 발생시켜서 테스트 케이스를 만들 수 있습니다.


위 예제에서는 간단하게 첫번째에 세팅한 ForefoxDriver로 제 웹사이트의 페이지 title을 얻어와서 콘솔에 뿌려지도록 만들었습니다.


위 클래스를 실행시키면 (Mouse right click -> Run As -> Java Application) Firefox 브라우저가 실행되서 gosolkit.com 페이지가 뜨고 크롬 부라우저에는 이 블로그가 그리고 마지막으로 IE 브라우저에는 Ashish의 웹페이지가 뜰 겁니다.


작업이 다 끝나면 콘솔에 제 웹사이트인 gosolkit.com 의 title이 찍힙니다.


반응형

Comment

이전 1 2 3 다음