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

최근에 받은 트랙백

글 보관함

calendar

        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  

Page Object Design Pattern

2014.08.01 10:43 | Posted by 솔웅


테스트 케이스를 만들 때 사용되는 Page Object Design Pattern에 대해 알아 보겠습니다.


우선 개념 파악부터 하고 넘어가죠.




이제 예제를 보겠습니다.


public class Login {

        public void testLogin() {
                selenium.type("inputBox", "testUser");
                selenium.type("password", "my supersecret password");
                selenium.click("sign-in");
                selenium.waitForPageToLoad("PageWaitPeriod");
                Assert.assertTrue(selenium.isElementPresent("compose button"),
                                "Login was unsuccessful");
        }
}

이 코드의 두가지 문제점

1. 테스트 메소드와 AUTs locators (이 예제에서는 ID 들) 들 간의 어떤 구분이 없다. 두개가 하나의 메소드에 그냥 얽혀 있다. 만약에 AUT의 UI가 그 identifiers, layout을 바꾸거나 로그인 방법을 바꾼다면 이 테스트 소스코드도 반드시 바뀌어야 한다.
2. id-locator들은 여러 다른 테스트에서도 사용될 것이다. 로그인을 해야 하는 모든 테스에서 사용될 것이다.

이 예제 대신에 Page Object technique을 사용하면 아래와 같이 고칠 수 있다.

public class SignInPage {

        private Selenium selenium;

        public SignInPage(Selenium selenium) {
                this.selenium = selenium;
                if(!selenium.getTitle().equals("Sign in page")) {
                        throw new IllegalStateException("This is not sign in page, current page is: "
                                        +selenium.getLocation());
                }
        }

        public HomePage loginValidUser(String userName, String password) {
                selenium.type("usernamefield", userName);
                selenium.type("passwordfield", password);
                selenium.click("sign-in");
                selenium.waitForPageToLoad("waitPeriod");

                return new HomePage(selenium);
        }
}

그리고 홈페이지에 대한 page object는 아래와 같을 것이다.

public class HomePage {

        private Selenium selenium;

        public HomePage(Selenium selenium) {
                if (!selenium.getTitle().equals("Home Page of logged in user")) {
                        throw new IllegalStateException("This is not Home Page of logged in user, current page" +
                                        "is: " +selenium.getLocation());
                }
        }

        public HomePage manageProfile() {
                // Page encapsulation to manage profile functionality
                return new HomePage(selenium);
        }

        /*More methods offering the services represented by Home Page
        of Logged User. These methods in turn might return more Page Objects
        for example click on Compose mail button could return ComposeMail class object*/

}

이제 로그인 테스트에서는 이 두 page object들을 아래와 같이 사용하면 된다.

public class TestLogin {

        public void testLogin() {
                SignInPage signInPage = new SignInPage(selenium);
                HomePage homePage = signInPage.loginValidUser("userName", "password");
                Assert.assertTrue(selenium.isElementPresent("compose button"),
                                "Login was unsuccessful");
        }
}





이 page object를 디자인 하는 방법은 여러가지가 있을 수 있다. 하지만 지켜야할 기본적인 룰은 지켜야 한다.
page object에는 어떤 verification이나 assertion을 만들면 안된다. 이 부분은 테스트의 한 부분이다. 그러므로 테스트 코드 내에 그런 기능이 있어야 한다. 절대 page object 내에 그것을 만들면 안된다. page object에는 페이지의 representation이 포함될 것이다.

page object에 들어갈 verification이 하나 있는데 그것은 해당 페이지를 verify 하는 부분이다. 혹은 해당 페이지의 아주 중요한 element도 될 수 있는데 그것은 해당 페이지가 제대로 load 됐는지를 확인하기 위한 부분이다. 이 verification은 해당 page object가 초기화 될 때 수행되어야 한다. 위 예제에서는 SignInPage와 HomePage 생성자가 그 기능을 수행한다.

page object는 전체 페이지를 represent할 필요는 없다. Page Object Design Pattern은 페이지안의 components를 represent하기 위해 사용된다. 만약 AUT안의 페이지가 여러 component들을 가지고 있다면 각 component별로 별도의 page object를 가지고 있게 되면 좀 더 유지관리하기 편할 것이다.

테스팅에 사용되는 다른 Design Pattern들도 있다. 어떤 경우에는 page object들을 instant화 하기 위해 Page Factory 패턴을 사용하기도 한다.


Selenium Wiki 에서 정의된 Page Object를 보려면 여기로 가시면 됩니다.

https://code.google.com/p/selenium/wiki/PageObjects



저작자 표시 비영리 동일 조건 변경 허락
신고


Selenium WebDriver로 테스트를 작성하다 보면 웹화면 입력할 데이터를 Testsuit(XML) 에 정의하고 그것을 받아서 일을 처리하는 경우가 많습니다.


데이터량이 많을 경우에는 많은 파라미터를 사용해야 하는데 그러면 번거로우니까 특정 문자로 데이터들을 구분하고 그것을 JAVA 파일에서 분리해서 배열에 담아 사용하면 편리한데요.


<parameter name="teststring" value="Hong|Gildong|Seoul|34|Male"/>


Test Suite 에 위와 같이 돼 있는 경우 자바 파일에서는 아래와 같이 사용할 수 있습니다.


@Parameters({"teststring"})


우선 teststring 파라미터를 위와 같이 지정하고.


public void testSplitString(String msg) throws Exception {
        List<String> msgList=Arrays.asList(msg.split("\\|"));
        otherClass.methodInOtherClass(msgList);
    }


이렇게 코드가 작성됩니다.


그러면 "|" 문자를 기준으로 Hong, Gildong, Seoul, 34, Mail 이 분리되서 msgList 에 담기고 이 리스트를 다른 비지니스를 구현하는 클래스의 해당 메소드로 패스해서 일을 처리하게 됩니다.



Split 이라는 유명한 관광지가 있나 봅니다. 크로아티아에....


Java - String split() Method


Description:


이 메소드는 2개의 variant를 가지고 있고 주어진 regular expression에 따라 String을 split 합니다.


Syntax:


이 메소드의 신택스는 아래와 같습니다.


public String[] split(String regex, int limit)

or

public String[] split(String regex)

Parameters:


아래는 파라미터들에 대한 설명입니다.

  • regex -- 구분 기준이 되는 regular expression.

  • limit -- return 될 String의 갯수 (result threshold)


Return Value:

  • 주어진 regular expression에 따라 String을 split 한 다음에 array를 return 하게 됩니다.


Example:


import java.io.*;

public class Test{
   public static void main(String args[]){
      String Str = new String("Welcome-to-Tutorialspoint.com");

      System.out.println("Return Value :" );
      for (String retval: Str.split("-", 2)){
         System.out.println(retval);
      }
      System.out.println("");
      System.out.println("Return Value :" );
      for (String retval: Str.split("-", 3)){
         System.out.println(retval);
      }
      System.out.println("");
      System.out.println("Return Value :" );
      for (String retval: Str.split("-", 0)){
         System.out.println(retval);
      }
      System.out.println("");
      System.out.println("Return Value :" );
      for (String retval: Str.split("-")){
         System.out.println(retval);
      }
   }
}


이렇게 하면 아래와 같은 결과를 얻을 수 있습니다.


Return Value :
Welcome
to-Tutorialspoint.com

Return Value :
Welcome
to
Tutorialspoint.com

Return Value:
Welcome
to
Tutorialspoint.com

Return Value :
Welcome
to
Tutorialspoint.com



저작자 표시 비영리 동일 조건 변경 허락
신고


요즘 Selenium WebDriver로 작업하는 웹 어플리케이션은 새로운 창을 아주 많이 열었다 닫았다 합니다.


그래서 테스트 케이스를 작성하다 보면 창을 옮겨 다녀야 되는 일이 많은데요.


브라우저들을 옮겨 다니는 방법을 확실하게 알아두기 위해서 구글링해서 몇개 소스를 분석해 보겠습니다.





//Store the current window handle
String winHandleBefore = driver.getWindowHandle();

//Perform the click operation that opens new window

//Switch to new window opened
for(String winHandle : driver.getWindowHandles()){
    driver.switchTo().window(winHandle);
}

// Perform the actions on new window

//Close the new window, if that window no more required
driver.close();

//Switch back to original browser (first window)

driver.switchTo().window(winHandleBefore);

//continue with original browser (first window)


이 소스가 가장 기본적인 소스인것 같습니다.

winHandleBefore 이라는 변수에 현재의 윈도우를 등록해 넣습니다.
그리고 for 문에서 현재 열려 있는 창들을 확인해서 switchTo를 합니다.

이러면 브라우저를 옮긴 겁니다.

다시 원래 브라우저로 돌아오려면 아까 parent 윈도우를 저장해 뒀던 변수로 다시 switchTo()를 해 주면 됩니다.

그런데 parent 윈도우가 있고 여기서 child 윈도우를 열었는데 이 child 윈도우에서 다시 또 child 윈도우를 여는 경우가 있습니다.


그러면 처음에 parent 윈도우를 변수에 담고 새창(2)을 엽니다.

그리고 새창(2)에서 다시 새창(3)을 열기 전에 새창(2)를 다른 변수에 담습니다.


그리고 원하는 창으로 다시 switchTo를 하면 되겠죠.

그런데 소스들을 찾다 보니까 좋은 코드가 있네요.


private void handleMultipleWindows(String windowTitle) {
            Set<String> windows = driver.getWindowHandles();

            for (String window : windows) {
                driver.switchTo().window(window);
                if (driver.getTitle().contains(windowTitle)) {
                    return;
                }
            }
  }


새창의 Title을 가지고 그 창으로 switchTo 하는 겁니다.


이러면 굳이 창을 변수에 담지 않아도 원하는 때에 원하는 창으로 간단하게 switchTo를 할 수 있겠네요.


내일 사무실에 가서 지금 일하고 있는 소스에 적용해 봐야 겠습니다.


String parentWindow= driver.getWindowHandle();
List<String> allWindows = driver.getWindowHandles(); for(String curWindow : allWindows){ driver.switchTo().window(curWindow); }
driver.close();
driver.switchTo().window(parentWindow);

이 소스도 아주 기본이 되는 소스네요.


오늘 좀 막혔던 부분을 내일 해결할 수 있을 것 같습니다.

저작자 표시 비영리 동일 조건 변경 허락
신고


오늘 일하다가 Selenium 으로 Double Click 을 구현해야 했습니다.


아래처럼 하면 됩니다.


Actions action = new Actions(WebDriverAction.getDriver());

action.doubleClick(element).perform();



근데 이게 잘 안 되더라구요.


HTML은 아래와 같은 형식이었거든요.


<SELECT style="FONT-FAMILY: Courier; FONT-SIZE: 10pt" ondblclick="runJavaScript('parameter')" size=8 name=select>
    <OPTION selected value="korea">
                South Korea      
    </OPTION>
</SELECT>


Select 메뉴 안에 있는 옵션을 더블 클릭하면 새로운 창이 떠오르도록 애플리케이션이 돼 있더라구요.



Select 메뉴라도 Dropdown 이 아니라 그냥 일반 Table 이나 div 처럼 화면에 다 표시 돼 있는 상황입니다.


여기에서 암만 위의 doubleClick 메소드를 사용해도 동작이 안 되더라구요.


한참 헤매다가 생각해 낸게 Double 클릭을 구현하지 말고 그냥 ondbclick 일 경우 실행되는 자바스크립트를 실행시키는 거 였습니다.


((JavascriptExecutor) WebDriverAction.getDriver()).executeScript("runJavaScript('parameter');");


이렇게 하면 됩니다.

퇴근하기 직전에 Debugging 하면서 한번 실행해 봤는데 새로운 창이 뜨더라구요.


내일 아침에 출근해서 전체 테스트 케이스를 실행해 봐야겠어요.


제대로 작동하길 바랍니다. ;;


Selenium Webdriver로 테스트 케이스를 구현할 때 제대로 동작하지 않는 event 가 있으면 이렇게 그냥 자바스크립트를 곧바로 실행시키는것도 좋은 방법인 것 같습니다.






저작자 표시 비영리 동일 조건 변경 허락
신고


지난 번 Selenium 관련 글에서 두개의 웹 어플리케이션에서 진행되는 flow를 하나의 테스트 케이스로 만드는 방법을 살펴 봤습니다.


아래와 같이 Selenium WebDriver의 Suite xml 파일에 <test> 라는 태그를 사용해서 진행할 수 있는 방법을 정리해 뒀었습니다.



<suite name="suite 이름">

     <listeners>
        <listener class-name=".........." />
    </listeners>
    <!-- GLOBAL PARAMETERS -->
    <parameter name="waitTime" value="40" />
    <parameter name="thinkTime" value="2" />

    <parameter name="app_url" value="웹 어플리케이션 URL" />
    <parameter name="username" value="아이디" />
    <parameter name="password" value="비밀번호" />
   
   
    <test verbose="10" name="이름 1" annotations="JDK" preserve-order="true">
        <classes>
            <class name="실행할 클래스 1" />
            <class name="실행할 클래스 2" />
            <class name="실행할 클래스 3" />
        </classes>
    </test>
   
    <test verbose="10" name="이름 2" annotations="JDK" preserve-order="true">
        <parameter name="browser" value="ie" />
        <parameter name="app_url1" value="웹 앱 URL 2" />
        <parameter name="username" value="아이디"" />
        <parameter name="password" value="비밀번호" />
       
        <classes>
            <class name="실행할 클래스 1" />
            <class name="실행할 클래스 2" />           
            <class name="실행할 클래스 3" />
        </classes>
    </test>
</suite>

첫번째 <test> 에서 사용하는 것은 일반 유저가 사용하는 웹 어플리케이션 이고 두번째 <test> 에서 사용하는 웹 어플리케이션은 관리자가 사용하는 것일 수 있는데요.


이 때 유저가 입력한 정보가 관리자 모드에서 제대로 표현 되는 지 여부를 테스트 해야 될 때가 있습니다.


예를 들어 첫번째 <test> 의 '실행할 클래스 3' 에서 유저가 물건을 주문했고 그 주문 번호가 1111111 일 경우.

두번째 <test> 에서는 이 주문번호가 제대로 입력이 됐는지. 그리고 그 주문번호에 따른 정보들이 제대로 들어가 있는지를 테스트 해야 될 수 있습니다.


이럴 경우 유저가 입력한 정보를 관리자모드에서 확인하도록 하는 방법은 여러 방법이 있겠습니다.


DB를 사용해서 정보를 가져와서 웹 페이지의 정보를 비교할 수 있겠고. 아니면 유저가 정보를 입력할 때 text나 다른 physical 한 파일 형태로 저장하고 관리자 모드에서 그 파일 안의 정보를 가져와서 테스트를 할 수 도 있구요.


그런데 단지 주문 번호 하나만 테스트를 해야 되는데 이렇게 DB 연결이나 물리적인 파일형태로 데이터를 저장하고 가져오는 것은 너무 복잡한 해결방법이 될 겁니다.


이 경우에는 User 모드에서 변수를 public static으로 저장하고 관리자 모드에서 그 정보를 가져와서 사용할 수 있습니다. (이것은 Selenium Webdriver에 대한 정보라기 보다는 자바 기초 정보입니다.)



예를 들어 위 코드내의 첫번째 <text>에 있는 '실행할 클래스 3' 에 아래와 같이 선언된 변수가 있습니다.


public static String orderNumber = null;

public static String userName = null;


그리고 유저가 이 정보를 입력하는 테스트 케이스에서 아래와 같이 이 변수에 그 정보를 담습니다.


@Test(alwaysRun = true)

public void inputOrderNumber() {

orderNumber = InputForm.getOrderNumber();

userName = InputForm.getUsername();

}


이 정보를 두번째 <test> 의 '실행할 클래스 3'에서 가져와서 해당 관리자모드 웹 페이지에 표시된 정보와 비교롤 합니다.


public static String orderNumber = null;

public static String userName = null;


@Test(alwaysRun = true)

public void checkOrderNumber() {

orderNumber = inputForm.orderNumber; (inputForm 은 첫번째 <test>의 '실행할 클래스3' 의 클래스 명)

}


오늘은 자바 기초 문법을 하나 정리 했네요.

저작자 표시 비영리 동일 조건 변경 허락
신고


ERP 웹 작업을 하다보면 일반 유저가 어떤 정보를 입력하고 관리자가 그 입력한 정보를 처리하는 프로세스들이 있습니다.


이 때 일반 유저가 입력할 때 사용하는 웹사이트와 관리자가 사용하는 웹사이트 즉 어플리케이션이 서로 다른 경우가 있습니다.


제가 참여하는 프로젝트에도 이런 경우가 있는데요.

거기에다가 일반 유저가 사용하는 웹어플리케이션은 아무 브라우저에서나 작동이 되는데 관리자가 사용하는 웹어플리케이션은 IE에서만 제대로 작동 됩니다.


그런데 테스트 케이스는 유저가 로그인해서 입력 완료하고 다시 관리자가 이를 처리하는 것 까지로 돼 있습니다.


이럴 경우 한개의 suite 에서 이 모든 일들을 처리할 수 있도록 해야 되는데요.


그럴 경우 아래와 같이 하면 됩니다.



<suite name="suite 이름">

     <listeners>
        <listener class-name=".........." />
    </listeners>
    <!-- GLOBAL PARAMETERS -->
    <parameter name="waitTime" value="40" />
    <parameter name="thinkTime" value="2" />

    <parameter name="app_url" value="웹 어플리케이션 URL" />
    <parameter name="username" value="아이디" />
    <parameter name="password" value="비밀번호" />
   
   
    <test verbose="10" name="이름 1" annotations="JDK" preserve-order="true">
        <classes>
            <class name="실행할 클래스 1" />
            <class name="실행할 클래스 2" />
            <class name="실행할 클래스 3" />
        </classes>
    </test>
   
    <test verbose="10" name="이름 2" annotations="JDK" preserve-order="true">
        <parameter name="browser" value="ie" />
        <parameter name="app_url1" value="웹 앱 URL 2" />
        <parameter name="username" value="아이디"" />
        <parameter name="password" value="비밀번호" />
       
        <classes>
            <class name="실행할 클래스 1" />
            <class name="실행할 클래스 2" />           
            <class name="실행할 클래스 3" />
        </classes>
    </test>
</suite>


이 테스트 suite 은 <suite>로 시작해서 </suite>으로 끝납니다.

listener를 작동해야 할 필요가 있으면 <listeners> 태그 안에 선언 합니다.


그 다음에 Parameter들을 선언하는 부분이 있습니다.

웹 URL이나 아이디 비밀번호 그 밖에 웹 페이지를 테스트할 때 필요한 파라미터들을 선언합니다.



이제 실제 실행될 테스트 케이스 클래스들을 선언할 차례인데요.

<test> 태그 안에 실행될 테스트 케이스 클래스들을 선언하시면 됩니다.


위에 보시면 두개의 <test> 태그가 있는데요.

첫번째 테스트에는 따로 파라미터가 선언돼 있지 않기 때문에 이 경우에는 Global Parameter를 사용합니다.


그리고 두번째는 따로 파라미터들을 선언했죠?

여기에 필요한 관리자용 어플리케이션 정보들을 선언해 주면 됩니다.


그리고 첫번째 테스트는 크롬 브라우저를 사용하고 두번째 브라우저는 IE 브라우저를 사용합니다.





이렇게 하나의 테스트 케이스에 여러 어플리케이션이나 여러 브라우저로 테스트 하도록 하는 방법은 <test> 태그를 여러개 사용해서 구현할 수 있습니다.



저작자 표시 비영리 동일 조건 변경 허락
신고


Internet Explorer Driver


인터넷 익스플로러드라이버는 webDriver의 wire 프로토콜을 implement한 standalone 서버 입니다. 이 드라이버는 XP, Vista, Windows 7에서 IE 6, 7, 8, 9 버전을 가지고 테스트를 했습니다.

이 드라이버는 브라우저의 32비트와 64 비트 버전을 지원합니다. 각 버전은 어떤 버전의 IEDriverServer.exe 에 따라 결정 됩니다. 32 비트 IEDriverServer.exe 가 실행이 되면 32비트 버전의 IE가 시작이 될 것이고 IEDriverServer.exe가 64비트라면 64비트 IE가 실행이 될 겁니다.

Installing


일단 standalon server 로 실행할 수 있는 IE버전다운로드 받아야 합니다. 그리고 여러분이 사용하는 PATH 에 복사해 넣습니다.


Pros (장점)

    Runs in a real browser and supports Javascript
    실제 브라우저가 실행되고 자바스크립트를 지원합니다.

Cons (단점)

    IEDriver는 Windows에서만 작동됩니다.
    Comparatively slow (though still pretty snappy :)
    비교적 느립니다.


Command-Line Switches


standalone으로 실행되니까, IE driver의 behavoir를 command-line argument들로 컨트롤 할 수 있습니다. 이 코맨드라인 argument의 값을 세팅하려면 여러분이 사용하는 language에 맞는 명령어를 사용해야 합니다. command line switch 는 아래 테이블에 있는 기능들을 지원합니다. -<switch>, --<switch> and /<switch> 가 사용 가능합니다.


Switch Meaning
--port=<portNumber> Specifies the port on which the HTTP server of the IE driver will listen for commands from language bindings. Defaults to 5555.
--host=<hostAdapterIPAddress> Specifies the IP address of the host adapter on which the HTTP server of the IE driver will listen for commands from language bindings. Defaults to 127.0.0.1.
--log-level=<logLevel> Specifies the level at which logging messages are output. Valid values are FATAL, ERROR, WARN, INFO, DEBUG, and TRACE. Defaults to FATAL.
--log-file=<logFile> Specifies the full path and file name of the log file. Defaults to stdout.
--extract-path=<path> Specifies the full path to the directory used to extract supporting files used by the server. Defaults to the TEMP directory if not specified.
--silent Suppresses diagnostic output when the server is started.




Important System Properties



아래의 시스템 프로퍼티들은 InternetExplorerDriver에 의해 사용됩니다. (자바의 경우 System.getProperty() and set using System.setProperty() 를 보세요. or the "-DpropertyName=value" command line flag)

Property What it means
webdriver.ie.driver The location of the IE driver binary.
webdriver.ie.driver.host Specifies the IP address of the host adapter on which the IE driver will listen.
webdriver.ie.driver.loglevel Specifies the level at which logging messages are output. Valid values are FATAL, ERROR, WARN, INFO, DEBUG, and TRACE. Defaults to FATAL.
webdriver.ie.driver.logfile Specifies the full path and file name of the log file.
webdriver.ie.driver.silent Suppresses diagnostic output when the IE driver is started.



Required Configuration


    - IEDriverServer 를 다운 받아서 해당 PATH에 복사해 넣어야 합니다.
    - Windows Vista나 Windows 7에서 IE 7 이상의 브라우저를 사용할 때 각 zone의 모드를 Protected Mode로 세팅 해야 합니다. 이 값들을 Tools 메뉴에서 on 이나 off로 세팅될 수 있습니다. 그리고 Security tab을 클릭하시면 됩니다. 각 zone에 보면 그 탭의 아래 부분에 체크박스가 있을 겁니다. 이 체크박스 (Enable Protected Mode)를 체크하시고 적용하시면 됩니다.
    - browser zoom level은 반드시 100%로 세팅되어야 합니다. 그래야 마우스 이벤트가 정확한 지점에서 일어날 수 있습니다. 






Native Events and Internet Explorer

IE드라이버는 윈도우즈에서만 돌아가기 때문에 브라우저에서 마우스나 키보드를 작동시킬 때는 OS level(이것을 native 라고 부르기도 합니다.)의 이벤트를 사용해야 됩니다.  같은 기능에 대해 시뮬레이트되는 자바스크립트 이벤트를 사용하는 것과 좀 차이가 있습니다.이 native 이벤트를 사용할 때의 장점은 JavaScript sandbox에 의존하지 않는 다는 겁니다. 그래서 브라우저 내에서 정확한 자바스크립트 이벤트를 사용할 수 있습니다. 하지만 현재 마우스 이벤트에 대한 몇가지 이슈들이 있는데요. IE 브라우저 윈도우가 focus를 잃어 버릴 때나 element들 위에 hover를 실행할 때에 이슈들이 좀 있습니다.



Browser Focus

The challenge is that IE itself appears to not fully respect the Windows messages we send the IE browser window (WM_MOUSEDOWN and WM_MOUSEUP) if the window doesn't have the focus. Specifically, the element being clicked on will receive a focus window around it, but the click will not be processed by the element. Arguably, we shouldn't be sending messages at all; rather, we should be using the SendInput() API, but that API explicitly requires the window to have the focus. We have two conflicting goals with the WebDriver project.

First, we strive to emulate the user as closely as possible. This means using native events rather than simulating the events using JavaScript.

Second, we want to not require focus of the browser window being automated. This means that just forcing the browser window to the foreground is suboptimal.

An additional consideration is the possibility of multiple IE instances running under multiple WebDriver instances, which means any such "bring the window to the foreground" solution will have to be wrapped in some sort of synchronizing construct (mutex?) within the IE driver's C++ code. Even so, this code will still be subject to race conditions, if, for example, the user brings another window to the foreground between the driver bringing IE to the foreground and executing the native event.

The discussion around the requirements of the driver and how to prioritize these two conflicting goals is ongoing. The current prevailing wisdom is to prioritize the former over the latter, and document that your machine will be unavailable for other tasks when using the IE driver. However, that decision is far from finalized, and the code to implement it is likely to be rather complicated.



Hovering Over Elements


When you attempt to hover over elements, and your physical mouse cursor is within the boundaries of the IE browser window, the hover will not work. More specifically, the hover will appear to work for a fraction of a second, and then the element will revert back to its previous state. The prevailing theory why this occurs is that IE is doing hit-testing of some sort during its event loop, which causes it to respond to the physical mouse position when the physical cursor is within the window bounds. The WebDriver development team has been unable to discover a workaround for this behavior of IE.



Clicking <option> Elements or Submitting Forms and alert()


There are two places where the IE driver does not interact with elements using native events. This is in clicking <option> elements within a <select> element. Under normal circumstances, the IE driver calculates where to click based on the position and size of the element, typically as returned by the JavaScript getBoundingClientRect() method. However, for <option> elements, getBoundingClientRect() returns a rectangle with zero position and zero size. The IE driver handles this one scenario by using the click() Automation Atom, which essentially sets the .selected property of the element and simulates the onChange event in JavaScript. However, this means that if the onChange event of the <select> element contains JavaScript code that calls alert(), confirm() or prompt(), calling WebElement's click() method will hang until the modal dialog is manually dismissed. There is no known workaround for this behavior using only WebDriver code.

Similarly, there are some scenarios when submitting an HTML form via WebElement's submit() method may have the same effect. This can happen if the driver calls the JavaScript submit() function on the form, and there is an onSubmit event handler that calls the JavaScript alert(), confirm(), or prompt() functions.

This restriction is filed as  issue 3508 .



Multiple instances of InternetExplorerDriver


With the creation of the IEDriverServer.exe, it should be possible to create and use multiple simultaneous instances of the InternetExplorerDriver. However, this functionality is largely untested, and there may be issues with cookies, window focus, and the like. If you attempt to use multiple instances of the IE driver, and run into such issues, consider using the RemoteWebDriver and virtual machines.

There are 2 solutions for problem with cookies (and another session items) shared between multiple instances of InternetExplorer.

The first is to start your InternetExplorer in private mode. After that InternetExplorer will be started with clean session data and will not save changed session data at quiting. To do so you need to pass 2 specific capabilities to driver: ie.forceCreateProcessApi with true value and ie.browserCommandLineSwitches with -private value. Be note that it will work only for InternetExplorer 8 and newer, and Windows Registry HKLM_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main path should contain key TabProcGrowth with 0 value.

The second is to clean session during InternetExplorer starting. For this you need to pass specific ie.ensureCleanSession capability with true value to driver. This clears the cache for all running instances of InternetExplorer, including those started manually.



Running IEDriverServer.exe Remotely


The HTTP server started by the IEDriverServer.exe sets an access control list to only accept connections from the local machine, and disallows incoming connections from remote machines. At present, this cannot be changed without modifying the source code to the IEDriverServer.exe. To run the Internet Explorer driver on a remote machine, use the Java standalone remote server in connection with your language binding's equivalent of RemoteWebDriver.

저작자 표시 비영리 동일 조건 변경 허락
신고


HTML 에 보면 Select 태그가 있습니다.

그 안에 여러 Option 들이 있고 유저들은 DropDown 메뉴에서 그 Option 중 하나를 선택하게 되죠.





여기서 이 Option을 선택하도록 하는 것을 Selenium WebDriver로 구현할 때 아래 두가지 방법을 사용할 수 있습니다.


new Select(WebDriverAction.getElement(By.cssSelector("select[name='state']"))).selectByVisibleText("North Carolina");


이렇게 하면 select 메뉴 중 name인 태그안에 있는 옵션 중에서 blue인 텍스트를 찾아서 선택을 해 줍니다.



이 방법을 아래와 같이 조금 복잡하게 처리할 수도 있습니다.


    WebElement select = driver.findElement(By.cssSelector("select[name='state']"));
    List<WebElement> options = select.findElements(By.tagName("option"));
    for(WebElement option : options){
        if(option.getText().equals("North Carolina")) {
            option.click();
            break;
        }
    }

이 로직은 name이 color 인 select 라는 tag를 찾아서 이것을 select라는 WebElement 변수에 담아 놓습니다.
그리고 이 select 안에서 tagName 이 option인 것들을 List<WebElement> type으로 options라는 변수에 담아 놓습니다.

이 리스트를 for문으로 돌려서 option의 text가 blue 인 것을 찾아서 그 WebElement를 click 합니다.

그러면 원하는 blue가 선택이 됩니다.



저작자 표시 비영리 동일 조건 변경 허락
신고



오늘은 Selenium WebDriver로 테스트 케이스를 만들다가 가끔 아주 유용하게 쓰이는 로직을 따로 정리합니다.


public static void sample01(String selectItem) throws Exception {

List<WebElement> sampleValue = driver.findElement(By.cssSelector("div[id='aaa'][class='bbb'] *"));


for(WebElement sample : sampleValue)

{

if(sample.getText().equalsIgnoreCase(selectItem))

sample.click();

}

}



위 코드는 클릭해야 되는 아이템이 딱히 unique 한 id나 class 뭐 이런걸 갖고 있지 않아서 Selenium으로 그 WebElement를 가져오기 힘들 때 아주 유용하게 사용하고 있습니다.


해당 WebElement의 상위 WebElement들 중 확실하게 unique 하게 추려낼 수 있는 WebElement를 sampleValue에다 담습니다. 위에서는 샘플로 id 가 aaa 이고 클래스가 bbb 인 div WebElement가 그에 해당됩니다.


이 div WebElement 내에는 또 다른 div나 tag들이 있을 겁니다.

for 문으로 이 sampeValue를 돌리면서 그 하위 WebElement들의 text들을 불러 옵니다.

이 텍스트가 원하는 텍스트와 같을 때 이 텍스트를 click 할 수 있습니다.


위 경우는 예를 들어 Edit이라는 링크가 있는데 해당 화면에는 이 Edit 이라는 링크가 많고 내가 딱히 클릭하고 싶은 Edit 링크는 어떤 unique 한 Attribute도 가지고 있지 않을 때 사용할 수 있습니다.

클릭하고자 하는 Edit을 감싸고 있는 부모 WebElement들 중에서 unique 한 속성을 가지고 있는 놈을 찾아서 List에 담고 이 리크트를 돌리면서 그 안에 있는 텍스트가 Edit이면 그것을 클릭하는 겁니다.

여기서 충족되어야 할 조건은 리스트에 담긴 부모 엘리먼트 안에는 Edit이라는 글자를 가지고 있는 WebElement가 내가 클릭하고자 하는 그 Edit WebElement 딱 하나라야 겠죠.





public static void pageNavigationSampe(String selectItem) throws Exception{

int exist = 0;

int firstPage = 0;

int pageNum = 1;


do{

if(firstPage==0) {

exist = checkAAAexist(selectItem);

firstPage=1;

} else {

pageNum = pageNum+1;

String PageCss = "a[id='goToPageId][pagenumber='" + pageNum + "']";

driver.findElement(By.cssSelector(PageCss)).click();

Thread.sleep(5000);

exist=checkAAAexist(selectItem);

}

} while(exist==0);

}


public static int checkAAAexist(String selectItem) throws Exception {

List<WebElement> theItem = driver.findElements(By.cssSelector("input[type='button'][value='theItem']"));

int exist = 0;


for(WebElement clickItem : theItem)

{

if(clickItem.getAttribute("onClick").contains(vehicle)) {

clickItem.click();

exist=1;

Thread.sleep(3000);

break;

}

}


return exist;

}


위 예제는 게시판 형태로 돼 있는 페이지 중에서 내가 선택하고자 하는 WebElement가 어떤 때는 첫번째 페이지에 있다가 또 어떤때는 두번째 페이지에 있고...

뭐 이렇게 테스트시마다 다른 페이지에 있을 수 있는 아이템을 다뤄야 할 때 사용할 수 있습니다.

상황은 클릭해야할 버튼이 있는데 이 버튼은 테이블의 각 row마다 있고 그 중 하나만 클릭해야 됩니다.

이 버튼을 나타내는 속성은 공통된 부분이 있을 겁니다.

그걸 checkAAAexist() 메소드에서 처럼 theItem 에 리스트로 담구요.

이 리스크를 for 문으로 돌리면서 원하는 텍스트를 가지고 있는 놈이 나오면 그 놈을 클릭합니다.

이건 위의 예제와 별반 다르지 않은데요.

문제는 이 페이지에 없으면 다음 페이지로 넘어가야 한다는 거죠.

그래서 pageNavigationSampe() 메소드를 만든겁니다.


처음에 checkAAAexist()를 호출해서 원하는 놈이 없다는 결론을 받으면 다음 페이지를 클릭하는 거죠.

여기서 중요한것은 각 페이지마다 걸려 있을 링크 (1,2,3,4... 이런 숫자에 링크들이 있겠죠.)..

이 링크들의 속성들의 규칙을 알아야 합니다.

대개 위 예제처럼 다 똑같고 1페이지 2페이지 3페이지 등등에 해당되는 링크들은 해당 숫자들이 들어가는 부분이 있을 겁니다.

그것을 위에서와 같이 해당 숫자 부분을 매번 +1 씩 해줘서 넣으면 계속 다음 페이지를 클릭할 수 있습니다.

만약에 원하는 놈이 나오면 클릭하고 break; 를 만나서 해당 루프를 빠져 나오겠죠.

위 로직에서는 이 break; 가 없어도 while() 문에서 체크해서 빠져 나오게 만들었지만.. 확실하게 하기 위해서 break; 문도 넣었습니다.

중간에 Thread.sleep()을 넣은 이유는 웹 UI에서는 링크를 클릭한 후 다음 페이지로 넘어가는데 시간이 걸리니까 곧바로 다음 Action을 취하면 Fail이 되는 경우가 많습니다.

그래서 강제로 Thread.sleep()을 넣어 준 겁니다.

원래 이상적인 방법은 다음 페이지에 나오는 특정 WebElement를 wait하는 방법이 있긴 한데요.

이 예제에서는 그것까지 다루지는 않겠습니다.


위 예제 중 Selenium WebDriver의 API와 약간 다른부분이 있을 수 있습니다.

제가 참여하고 있는 프로젝트에서는 이 Selenium WebDriver를 편리하게 다루가 위한 프레임워크를 따로 제작해서 사용하고 있거든요.

그래서 그 프레임워크의 API가 있는 부분은 따로 Selenium WebDirver의 API로 풀어서 넣었는데요.

직접 돌려서 결과를 해보면서 코드를 바꾼에 아니라서 혹시 맞지 않는 부분이 있을 수 있습니다.

참고하세요.


저작자 표시 비영리 동일 조건 변경 허락
신고


오늘 배운 Tip 하나 정리 해 둡니다.


Alert 창 떴을 때 Control 하는 법


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

alert.accept();


public void checkAlert() {
    try {
        WebDriverWait wait = new WebDriverWait(driver, 2);
        wait.until(ExpectedConditions.alertIsPresent());
        Alert alert = driver.switchTo().alert();
        alert.accept();
    } catch (Exception e) {
        //exception handling
    }
}


driver.switchTo().alert().accept();
or
driver.switchTo().alert().dismiss();

// Get a handle to the open alert, prompt or confirmation
Alert alert = browser.switchTo().alert();
// Get the text of the alert or prompt
alert.getText();
// And acknowledge the alert (equivalent to clicking "OK")
alert.accept();

WebDriver driver = new FirefoxDriver();
driver.get("http://localhost:8081/TestAutomation/Escape.jsp");
driver.manage().window().maximize();

WebElement txtBxHandle = driver.findElement(By.name("txtName"));        
txtBxHandle.sendKeys("Socrates");

Actions action = new Actions(driver);
action.sendKeys(Keys.ESCAPE).perform();

WebElement BnEnable = driver.findElement(By.name("btnSubmit"));
BnEnable.click();


저작자 표시 비영리 동일 조건 변경 허락
신고
이전 1 2 3 다음

티스토리 툴바