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

최근에 받은 트랙백

글 보관함

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