SeleniumWebDriver
 使ってみようず

       2012/04/07 お だ


    わんくま同盟 大阪勉強会 #48
自己紹介

• 織田 信亮(おだ しんすけ)
• 大阪で開発者しています
• SQLWorld 代表 (http://sqlworld.org)

• http://d.hatena.ne.jp/odashinsuke/
• Twitter:@shinsukeoda




                わんくま同盟 大阪勉強会 #48
~基本~




わんくま同盟 大阪勉強会 #48
Selenium ってなに?

• Web アプリケーション用のテストツール
• ブラウザを使って Web アプリケーション
  の動作確認等を行う
• ブラウザの操作を Selenium が行ってくれ
  る




         わんくま同盟 大阪勉強会 #48
Selenium WebDriver ってなに?

http://seleniumhq.org/docs/03_webdriver.html
• Selenium が WebDriver と統合された
• Selenium 1.0 だと JavaScript/HTML で記
  述がメイン
• WebDriver は、Selenium ではセキュリ
  ティで制限されていたものが回避出来る
• Selenium 2.0 で統合!



                 わんくま同盟 大阪勉強会 #48
API が提供されている言語

•   Java
•   C#
•   Python
•   Ruby
•   PHP
•   Perl




               わんくま同盟 大阪勉強会 #48
提供されている WebDriver

•   HtmlUnit Driver
•   Firefox Driver
•   Internet Explorer Driver
•   Chrome Driver
•   Opera Driver
•   iPhone Driver
•   Android Driver
    言語によっては、提供されていない Driver もあ
    る!

                  わんくま同盟 大阪勉強会 #48
API の基本

• ドライバー
 – IWebDriver (WebDriver)
• エレメント
 – IWebElement(WebElement)
• ロケーター
 – By




               わんくま同盟 大阪勉強会 #48
とりあえず、ブラウザ起動してみる

using System;
using OpenQA.Selenium.IE;
using OpenQA.Selenium;

class Program {
  static void Main(string[] args) {
    IWebDriver driver = new InternetExplorerDriver();
    Console.ReadKey();
    driver.Quit();
  }
}




                     わんくま同盟 大阪勉強会 #48
ドライバー の API

• ページのタイトル取得
• 要素の検索
 – ISearchContext を実装
   • FindElement, FindElements
• ページ遷移
 – INavigation を保持
   • GoToUrl, Back, Forward
• コンテキストの切り替え
 – ITargetLocator を保持
   • Alert, Frame, Window

                わんくま同盟 大阪勉強会 #48
Bing にいってみる

using System;
using OpenQA.Selenium.IE;
using OpenQA.Selenium;

class Program {
  static void Main(string[] args) {
    IWebDriver driver = new InternetExplorerDriver();
    driver.Navigate().GoToUrl("http://www.bing.com");
    Console.WriteLine(driver.Title);
    Console.ReadKey();
    driver.Quit();
  }
}




                     わんくま同盟 大阪勉強会 #48
テキストボックスに文字を入力

using System;
using OpenQA.Selenium.IE;
using OpenQA.Selenium;

class Program {
  static void Main(string[] args) {
    IWebDriver driver = new InternetExplorerDriver();
    driver.Navigate().GoToUrl("http://www.bing.com");
    IWebElement element = driver.FindElement(By.Name("q"));
    element.SendKeys("セレニウム ウェブドライバー");
    Console.ReadKey();
    driver.Quit();
  }
}




                       わんくま同盟 大阪勉強会 #48
わんくま同盟 大阪勉強会 #48
ロケーターには何がある?

•   Id
•   Name
•   TagName
•   ClassName
•   CssSelector
•   LinkText
•   PartialLinkText
•   XPath

                  わんくま同盟 大阪勉強会 #48
using System;
                     色んな取り方をしてみる
using OpenQA.Selenium.IE;
using OpenQA.Selenium;

class Program {
  static void Main(string[] args) {
    IWebDriver driver = new InternetExplorerDriver();
    driver.Navigate().GoToUrl("http://www.bing.com");
    IWebElement elementByName = driver.FindElement(By.Name("q"));
    elementByName.SendKeys("セレニウム ウェブドライバー");
    IWebElement elementById = driver.FindElement(By.Id("sb_form_q"));
    elementById.SendKeys(" ID で取ったお");
    IWebElement elementByCss = driver.FindElement(
      By.CssSelector("input.sw_qbox"));
    elementByCss.Clear();
    elementByCss.SendKeys("CssSelector で");
    Console.ReadKey();
    driver.Quit();
  }
}




                            わんくま同盟 大阪勉強会 #48
エレメント の メソッド

•   SendKeys
•   Clear
•   Click
•   GetAttribute
    – input タグの入力値はこれで取得する
• GetCssValue
• Submit
• 要素の検索 (ISearchContext を実装)

                   わんくま同盟 大阪勉強会 #48
エレメント の プロパティ

基本 get だけ
• Displayed
• Enabled
• Location
• Selected
  – チェックボックスや Select の Option
• Size
• TagName
• Text
  – タグに挟まれたテキストのこと
  – テキストボックスの値じゃない!

                わんくま同盟 大阪勉強会 #48
~実践~




わんくま同盟 大阪勉強会 #48
みんな大好き IE Driver を使う

• 前準備
 – IE がインストールされている
 – ツール => インターネット オプション => セ
   キュリティ タブ => 全てのゾーンで「保護
   モードを有効にする」チェック値を統一




            わんくま同盟 大阪勉強会 #48
Chrome Driver を使う

• 前準備
 – Chrome がインストールされている
 – ChromeDriver.exe をダウンロードする
 http://code.google.com/p/chromedriver/downloads/list




                  わんくま同盟 大阪勉強会 #48
C# で

• Visual Web Developer 2010 Express
  (VWD2010)
• 拡張機能マネージャーから NuGet インス
  トール
• Package Manage Console(NuGet) から
    Install-Package Selenium.WebDriver
    Install-Package Selenium.Support
  – Support は便利だからいれてます
     ここでは、以下のライブラリも利用しています
     Nunit、ChainingAssertion.NUnit

                 わんくま同盟 大阪勉強会 #48
[Test]
public void 検索() {
  var driver = new InternetExplorerDriver();
  try {
    driver.Navigate().GoToUrl("http://www.bing.com");
    var txt条件 = driver.FindElementByName("q");
    txt条件.SendKeys("Microsoft");
    txt条件.Submit();
    Thread.Sleep(3000); // 次の画面に遷移するまで待つ
    var lbl件数 = driver.FindElementById("count");
    Regex.Match(lbl件数.Text,
      "(?<=of ).*(?= results)").Value.Is("527,000,000");
  } finally {
    driver.Quit();
  }
}




                     わんくま同盟 大阪勉強会 #48
便利なやつ その1

• IWait(Wait)
  – Selenium.Support に含まれている
     • OpenQA.Selenium.Support.UI.IWait
  – Thread.Sleep はもう古い!
  – 指定条件を満たすまで待機する
  – タイムアウト指定することで、異常時には例
    外で終了する




                  わんくま同盟 大阪勉強会 #48
Wait

•   WebDriverWait が良く使われる
•   コンストラクタでタイムアウト時間指定
•   Until メソッドに Func を渡し条件指定
•   Func は、既定の実装が幾つかある
    – ExpectedConditions
    IWait<IWebDriver> wait =
      new WebDriverWait(driver, new TimeSpan(0, 0,10));
    wait.Until(ExpectedConditions.TitleIs("Microsoft - Bing"));

• Func を自前で実装も可
    wait.Until(d => d.Title == "Microsoft - Bing");

                       わんくま同盟 大阪勉強会 #48
[Test]
public void 検索() {
  var driver = new InternetExplorerDriver();
  try {
    driver.Navigate().GoToUrl("http://www.bing.com");
    var txt条件 = driver.FindElementByName("q");
    txt条件.SendKeys("Microsoft");
    txt条件.Submit();
    var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
    wait.Until(ExpectedConditions.TitleIs("Microsoft - Bing"));
    var lbl件数 = driver.FindElementById("count");
    Regex.Match(lbl件数.Text,
       "(?<=of ).*(?= results)").Value.Is("527,000,000");
  } finally {
    driver.Quit();
  }
}




                       わんくま同盟 大阪勉強会 #48
PageObject パターン

• 一つの HTML の操作は一つの場所で
• 一つのページを一つのオブジェクトとして
  扱い、カプセル化
• メソッドは実行する機能を表現する(DOM
  の操作ではない)
 http://memolog.org/2010/11/page_objects.php
 http://code.google.com/p/selenium/wiki/PageObjects




                     わんくま同盟 大阪勉強会 #48
[TestFixture]
public class カプセル化 {
  [Test]
  public void 検索() {
    var driver = new InternetExplorerDriver();
    try {
      var instance = BingSearch.Create(driver);
      instance.Input検索条件("Microsoft");
      instance.Submit検索();
      instance.Get検索結果件数().Is("527,000,000");
    } finally {
      driver.Quit();
    }
  }
}




                   わんくま同盟 大阪勉強会 #48
public class BingSearch {
  public static BingSearch Create(RemoteWebDriver driver) {
    var instance = new BingSearch(driver);
    driver.Url = "http://www.bing.com";
    return instance;
  }
  private readonly RemoteWebDriver driver;
  private BingSearch(RemoteWebDriver driver) {
    this.driver = driver;
  }
  private IWebElement txt条件 {
    get { return driver.FindElementByName("q"); }
  }
  private IWebElement lbl件数 {
    get { return driver.FindElementById("count"); }
  }




                     わんくま同盟 大阪勉強会 #48
public void Input検索条件(string 条件) {
    this.txt条件.Clear();
    this.txt条件.SendKeys(条件);
  }
  public void Submit検索() {
    this.txt条件.Submit();
    var wait = new WebDriverWait(this.driver,
      new TimeSpan(0, 0, 10));
    wait.Until(ExpectedConditions.TitleIs(
      "Microsoft - Bing"));
  }
  public string Get検索結果件数() {
    return Regex.Match(this.lbl件数.Text,
      "(?<=of ).*(?= results)").Value;
  }
}




                     わんくま同盟 大阪勉強会 #48
Java (Maven) で

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

• ie-driver や support もついてくる




                     わんくま同盟 大阪勉強会 #48
@Test
public void 検索() {
  RemoteWebDriver driver = new InternetExplorerDriver();
  try {
    driver.navigate().to("http://www.bing.com");
    WebElement txt条件 = driver.findElementByName("q");
    txt条件.sendKeys("Microsoft");
    txt条件.submit();
    Wait<WebDriver> wait = new WebDriverWait(driver, 10);
    wait.until(titleIs("Microsoft - Bing"));
    WebElement lbl件数 = driver.findElementById("count");
    assertThat(lbl件数.getText().replaceAll(
        "(.*of )(.*)( results)", "$2"),
      is("527,000,000"));
  } finally {
    driver.quit();
  }
}


                     わんくま同盟 大阪勉強会 #48
@Test
public void カプセル化() {
  RemoteWebDriver driver = new InternetExplorerDriver();
  try {
    BingSearch instance = BingSearch.create(driver);
    instance.input検索条件("Microsoft");
    instance.submit検索();
    assertThat(instance.get検索結果件数(),
      is("527,000,000"));
  } finally {
    driver.quit();
  }
}




                     わんくま同盟 大阪勉強会 #48
public class BingSearch {
  private final RemoteWebDriver driver;
  public static BingSearch create(RemoteWebDriver driver) {
    BingSearch instance = new BingSearch(driver);
    driver.navigate().to("http://www.bing.com");
    return instance;
  }
  private BingSearch(RemoteWebDriver driver) {
    this.driver = driver;
  }
  private WebElement txt条件() {
    return driver.findElementByName("q");
  }
  private WebElement lbl件数() {
    return driver.findElementById("count");
  }




                     わんくま同盟 大阪勉強会 #48
public void input検索条件(String 条件) {
      this.txt条件().clear();
      this.txt条件().sendKeys(条件);
    }
    public void submit検索() {
      this.txt条件().submit();
      Wait<WebDriver> wait = new WebDriverWait(driver, 10);
      wait.until(titleIs("Microsoft - Bing"));
    }
    public String get検索結果件数() {
      return this.lbl件数().getText().replaceAll(
        "(.*of )(.*)( results)", "$2");
    }
}
             Java だとプロパティ(getter)
                     の
                 括弧 が鬱陶しい!

                       わんくま同盟 大阪勉強会 #48
便利なやつ (その2)

• PageFactory
  – PageObject の実装を少し楽にしてくれる
  – アノテーション/属性 ベースで、要素とフィー
    ルドのマッピング
    • WebElement 型の フィールド
  – キャッシュも可能
    • ページ遷移/リロードを行った場合は、キャッシュ
      を取り直す必要あり
  – PageFactory.initElements で初期化を行う


                わんくま同盟 大阪勉強会 #48
public class Top {
  public static Top create(WebDriver driver) {
    driver.navigate().to("http://www.bing.com");
    Top instance = new Top(driver);
    PageFactory.initElements(driver, instance);
    return instance;
  }
  private final WebDriver driver;
  private Top(WebDriver driver) {
    this.driver = driver;
  }

 @FindBy(name = "q")
 @CacheLookup
 private WebElement txt条件;




                     わんくま同盟 大阪勉強会 #48
public Result search(String 条件) {
      this.txt条件.clear();
      this.txt条件.sendKeys(条件);
      this.txt条件.submit();
      Wait<WebDriver> wait = new WebDriverWait(driver, 10);
      wait.until(titleIs(条件 + " - Bing"));

        return Result.create(driver);
    }
}




                         わんくま同盟 大阪勉強会 #48
public class Result {
  public static Result create(WebDriver driver) {
    return PageFactory.initElements(driver, Result.class);
  }
  private final WebDriver driver;
  public Result(WebDriver driver) {
    this.driver = driver;
  }

    @FindBy(id="count")
    private WebElement lbl件数;

    public String 検索結果件数() {
      return lbl件数.getText()
        .replaceAll("(.*of )(.*)( results)", "$2");
    }
}



                       わんくま同盟 大阪勉強会 #48
便利なやつ(その3)

• Select
  – input type=“select” な WebElement のラッ
    パー
  – Option の選択や取得を容易にしてくれる
  – PageFactory には対応していない




               わんくま同盟 大阪勉強会 #48
Select
WebElement select = ~;
List<WebElement> options =
  select.findElements(By.tagName("option"));
for (WebElement option : options) {
  option.click(); // 選択させる
  if (option.isSelected()) { // 選択していたら
  }
}
Select wrapper = new Select(select);
// 選択させる
wrapper.selectByIndex(0);
wrapper.selectByValue("hoge");
wrapper.selectByVisibleText("フヒヒ");
// 選択されているもの取得
wrapper.getFirstSelectedOption();
wrapper.getAllSelectedOptions();


                    わんくま同盟 大阪勉強会 #48
よく使いそうな操作

•   Table 表示のデータ取得
•   スクリーンショットの取得
•   input type=“file” へのパス指定
•   Alert/Confirm ダイアログ
•   新しい Window




               わんくま同盟 大阪勉強会 #48
Table 表示のデータ取得

• Java だとこんな感じ…
 – 1行を表すデータ型作成
 – <tr> 単位でループし、コレクションの取得
   • PageFactory 等を使用しインスタンス生成
 – 比較処理
• .NET だと…




             わんくま同盟 大阪勉強会 #48
[Test]
public void Table() {
  var driver = new ChromeDriver(@"c:work");
  try {
    driver.Url = "http://nabewebdriver.apphb.com/";
    var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
    wait.Until(d => d.Title == "メニュー");
    driver.FindElementByPartialLinkText("検索画面").Click();
    wait.Until(d => d.Title == "Search");
    driver.FindElementByXPath("//input[@type='submit' and @value='検索']").Click();
    wait.Until(ExpectedConditions.ElementIsVisible(By.Id("results")));
    driver.FindElementsById("roop").Select(e => new {
       Name = e.FindElement(By.Id("resultName")).Text,
       Birthday = e.FindElement(By.Id("resultBirthday")).Text,
       Money = e.FindElement(By.Id("resultMoney")).Text
    }).Is(
       new { Name = "名前1", Birthday = "1970/12/04", Money = "10,000" },
       new { Name = "名前2", Birthday = "1980/10/15", Money = "15,000" },
       new { Name = "名前3", Birthday = "1979/06/23", Money = "20,000" },
       new { Name = "名前4", Birthday = "1990/08/06", Money = "25,000" },
       new { Name = "名前5", Birthday = "2000/07/04", Money = "30,000" }
    );
  } finally {
    driver.Quit();
  }
}


                             わんくま同盟 大阪勉強会 #48
driver.FindElementsById("roop").Select(e => new {
  Name = e.FindElement(By.Id("resultName")).Text,
  Birthday = e.FindElement(By.Id("resultBirthday")).Text,
  Money = e.FindElement(By.Id("resultMoney")).Text
}).Is(
  new { Name = "名前1", Birthday = "1970/12/04",
    Money = "10,000" },
  new { Name = "名前2", Birthday = "1980/10/15",
    Money = "15,000" },
  new { Name = "名前3", Birthday = "1979/06/23",
    Money = "20,000" },
  new { Name = "名前4", Birthday = "1990/08/06",
    Money = "25,000" },
  new { Name = "名前5", Birthday = "2000/07/04",
    Money = "30,000" }
);




                     わんくま同盟 大阪勉強会 #48
スクリーンショットの取得

• TakesScreenshot を実装している Driver
  が対象
 – 殆どの Driver は実装している
• Java だと…
  FileUtils.copyFile(
    driver.getScreenshotAs(OutputType.FILE),
    new File("c:/work/hoge.png")
  );

• NET だと…
  driver.GetScreenshot().SaveAsFile(
    @"c:workhoge.png", ImageFormat.Png);



                    わんくま同盟 大阪勉強会 #48
input type=“file” へのパス指定

• WebElement を取得し、sendKeys でフル
  パスを渡す。
• Java だと…
  driver.findElement(By.id("fileupload"))
    .sendKeys("c:/work/result.jpg");


• NET だと…
  driver.FindElement(By.Id("fileupload"))
    .SendKeys(@"c:workresult.jpg");




                  わんくま同盟 大阪勉強会 #48
Alert/Confirm ダイアログ

• WebDriver から TargetLocator を取得し、
  alert を呼ぶ。
• Java だと…
  Alert dialog = driver.switchTo().alert();

• NET だと…
  var dialog = driver.SwitchTo().Alert();




                  わんくま同盟 大阪勉強会 #48
Alert インターフェース

• getText
  – 表示しているテキストを取得
• accept
  – OK ボタンクリック
• dismiss
  – キャンセル ボタンクリック
• sendKeys



              わんくま同盟 大阪勉強会 #48
Alert/Confirm ダイアログ 注意点

• ダイアログが表示されている間は他の操作
  は出来ない
  – Driver や Element の操作
• accept/dismiss した後に Alert を操作
  – 閉じている Dialog は操作出来ない
• Alert を取得する際は、念のため Wait を使
  う



              わんくま同盟 大阪勉強会 #48
エラーになるケース

HTML
<input type="button" id="btn" value="hoge“
  onclick="alert('hoge');" />
<input type="text" id="txt" />


C# コード
var text = driver.FindElementById("txt");
driver.FindElementById("btn").Click();
// text.SendKeys("hoge"); // Error
// driver.FindElementById("button"); // Error
var dialog = driver.SwitchTo().Alert();
dialog.Accept();
var dialogText = dialog.Text; // Error



                    わんくま同盟 大阪勉強会 #48
Alert 取得時の Wait

• Java だと…
 Wait<WebDriver> wait =
   new WebDriverWait(driver, 10);
 Alert dialog = wait.until(alertIsPresent());

• NET だと…
 var wait = new WebDriverWait(
   driver, new TimeSpan(0, 0, 10));
 var dialog = wait.Until(d => {
   try { return d.SwitchTo().Alert(); }
   catch (Exception) { return null;}
 });




                  わんくま同盟 大阪勉強会 #48
新しい Window

• WebDriver から TargetLocator を取得し、
  window を呼ぶ。
 – 戻り値は WebDriver で呼び出し元と同じイン
   スタンス
• Java だと…
  driver.switchTo().window("name or handler");

• NET だと…
  driver.SwitchTo().Window("name");
    // 一応 handler でもOK



                  わんくま同盟 大阪勉強会 #48
WindowHandler の取得

• Java だと…
 String current = driver.getWindowHandle();
 Set<String> all = driver.getWindowHandles();


• NET だと…
 var current = driver.CurrentWindowHandle;
 var all = driver.WindowHandles;




                  わんくま同盟 大阪勉強会 #48
新しい Window 切替時の Wait

• Java だと…
 Wait<WebDriver> wait = new WebDriverWait(driver, 10);
 wait.until(new Function<WebDriver, WebDriver>() {
   public WebDriver apply(WebDriver arg0) {
     try { return arg0.switchTo().window("windowName"); }
     catch (Exception e) { return null; }
   }
 });

• NET だと…
 var wait = new WebDriverWait(
   driver, new TimeSpan(0, 0, 10));
 wait.Until(d => {
   try { return d.SwitchTo().Window("windowName"); }
   catch (Exception) { return null;}
 });




                       わんくま同盟 大阪勉強会 #48
~まとめ~




わんくま同盟 大阪勉強会 #48
まとめ
• 複数の言語/ブラウザに対応している
 – Java が API が充実してそう
• 大概のことは出来ます
 – 今回説明省いたきましたが、Interactions を使
   えば、Drag&Drop みたいな事も
 http://code.google.com/p/selenium/wiki/AdvancedUserInteractions#
 Mouse_interactions

• Wait 超大事!
• 当然テスト以外でも使えます
 – ブラウザ操作の自動化
                     わんくま同盟 大阪勉強会 #48

Selenium webdriver使ってみようず

  • 1.
    SeleniumWebDriver 使ってみようず 2012/04/07 お だ わんくま同盟 大阪勉強会 #48
  • 2.
    自己紹介 • 織田 信亮(おだしんすけ) • 大阪で開発者しています • SQLWorld 代表 (http://sqlworld.org) • http://d.hatena.ne.jp/odashinsuke/ • Twitter:@shinsukeoda わんくま同盟 大阪勉強会 #48
  • 3.
  • 4.
    Selenium ってなに? • Webアプリケーション用のテストツール • ブラウザを使って Web アプリケーション の動作確認等を行う • ブラウザの操作を Selenium が行ってくれ る わんくま同盟 大阪勉強会 #48
  • 5.
    Selenium WebDriver ってなに? http://seleniumhq.org/docs/03_webdriver.html •Selenium が WebDriver と統合された • Selenium 1.0 だと JavaScript/HTML で記 述がメイン • WebDriver は、Selenium ではセキュリ ティで制限されていたものが回避出来る • Selenium 2.0 で統合! わんくま同盟 大阪勉強会 #48
  • 6.
    API が提供されている言語 • Java • C# • Python • Ruby • PHP • Perl わんくま同盟 大阪勉強会 #48
  • 7.
    提供されている WebDriver • HtmlUnit Driver • Firefox Driver • Internet Explorer Driver • Chrome Driver • Opera Driver • iPhone Driver • Android Driver 言語によっては、提供されていない Driver もあ る! わんくま同盟 大阪勉強会 #48
  • 8.
    API の基本 • ドライバー – IWebDriver (WebDriver) • エレメント – IWebElement(WebElement) • ロケーター – By わんくま同盟 大阪勉強会 #48
  • 9.
    とりあえず、ブラウザ起動してみる using System; using OpenQA.Selenium.IE; usingOpenQA.Selenium; class Program { static void Main(string[] args) { IWebDriver driver = new InternetExplorerDriver(); Console.ReadKey(); driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 10.
    ドライバー の API •ページのタイトル取得 • 要素の検索 – ISearchContext を実装 • FindElement, FindElements • ページ遷移 – INavigation を保持 • GoToUrl, Back, Forward • コンテキストの切り替え – ITargetLocator を保持 • Alert, Frame, Window わんくま同盟 大阪勉強会 #48
  • 11.
    Bing にいってみる using System; usingOpenQA.Selenium.IE; using OpenQA.Selenium; class Program { static void Main(string[] args) { IWebDriver driver = new InternetExplorerDriver(); driver.Navigate().GoToUrl("http://www.bing.com"); Console.WriteLine(driver.Title); Console.ReadKey(); driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 12.
    テキストボックスに文字を入力 using System; using OpenQA.Selenium.IE; usingOpenQA.Selenium; class Program { static void Main(string[] args) { IWebDriver driver = new InternetExplorerDriver(); driver.Navigate().GoToUrl("http://www.bing.com"); IWebElement element = driver.FindElement(By.Name("q")); element.SendKeys("セレニウム ウェブドライバー"); Console.ReadKey(); driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 13.
  • 14.
    ロケーターには何がある? • Id • Name • TagName • ClassName • CssSelector • LinkText • PartialLinkText • XPath わんくま同盟 大阪勉強会 #48
  • 15.
    using System; 色んな取り方をしてみる using OpenQA.Selenium.IE; using OpenQA.Selenium; class Program { static void Main(string[] args) { IWebDriver driver = new InternetExplorerDriver(); driver.Navigate().GoToUrl("http://www.bing.com"); IWebElement elementByName = driver.FindElement(By.Name("q")); elementByName.SendKeys("セレニウム ウェブドライバー"); IWebElement elementById = driver.FindElement(By.Id("sb_form_q")); elementById.SendKeys(" ID で取ったお"); IWebElement elementByCss = driver.FindElement( By.CssSelector("input.sw_qbox")); elementByCss.Clear(); elementByCss.SendKeys("CssSelector で"); Console.ReadKey(); driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 16.
    エレメント の メソッド • SendKeys • Clear • Click • GetAttribute – input タグの入力値はこれで取得する • GetCssValue • Submit • 要素の検索 (ISearchContext を実装) わんくま同盟 大阪勉強会 #48
  • 17.
    エレメント の プロパティ 基本get だけ • Displayed • Enabled • Location • Selected – チェックボックスや Select の Option • Size • TagName • Text – タグに挟まれたテキストのこと – テキストボックスの値じゃない! わんくま同盟 大阪勉強会 #48
  • 18.
  • 19.
    みんな大好き IE Driverを使う • 前準備 – IE がインストールされている – ツール => インターネット オプション => セ キュリティ タブ => 全てのゾーンで「保護 モードを有効にする」チェック値を統一 わんくま同盟 大阪勉強会 #48
  • 20.
    Chrome Driver を使う •前準備 – Chrome がインストールされている – ChromeDriver.exe をダウンロードする http://code.google.com/p/chromedriver/downloads/list わんくま同盟 大阪勉強会 #48
  • 21.
    C# で • VisualWeb Developer 2010 Express (VWD2010) • 拡張機能マネージャーから NuGet インス トール • Package Manage Console(NuGet) から Install-Package Selenium.WebDriver Install-Package Selenium.Support – Support は便利だからいれてます ここでは、以下のライブラリも利用しています Nunit、ChainingAssertion.NUnit わんくま同盟 大阪勉強会 #48
  • 22.
    [Test] public void 検索(){ var driver = new InternetExplorerDriver(); try { driver.Navigate().GoToUrl("http://www.bing.com"); var txt条件 = driver.FindElementByName("q"); txt条件.SendKeys("Microsoft"); txt条件.Submit(); Thread.Sleep(3000); // 次の画面に遷移するまで待つ var lbl件数 = driver.FindElementById("count"); Regex.Match(lbl件数.Text, "(?<=of ).*(?= results)").Value.Is("527,000,000"); } finally { driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 23.
    便利なやつ その1 • IWait(Wait) – Selenium.Support に含まれている • OpenQA.Selenium.Support.UI.IWait – Thread.Sleep はもう古い! – 指定条件を満たすまで待機する – タイムアウト指定することで、異常時には例 外で終了する わんくま同盟 大阪勉強会 #48
  • 24.
    Wait • WebDriverWait が良く使われる • コンストラクタでタイムアウト時間指定 • Until メソッドに Func を渡し条件指定 • Func は、既定の実装が幾つかある – ExpectedConditions IWait<IWebDriver> wait = new WebDriverWait(driver, new TimeSpan(0, 0,10)); wait.Until(ExpectedConditions.TitleIs("Microsoft - Bing")); • Func を自前で実装も可 wait.Until(d => d.Title == "Microsoft - Bing"); わんくま同盟 大阪勉強会 #48
  • 25.
    [Test] public void 検索(){ var driver = new InternetExplorerDriver(); try { driver.Navigate().GoToUrl("http://www.bing.com"); var txt条件 = driver.FindElementByName("q"); txt条件.SendKeys("Microsoft"); txt条件.Submit(); var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10)); wait.Until(ExpectedConditions.TitleIs("Microsoft - Bing")); var lbl件数 = driver.FindElementById("count"); Regex.Match(lbl件数.Text, "(?<=of ).*(?= results)").Value.Is("527,000,000"); } finally { driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 26.
    PageObject パターン • 一つのHTML の操作は一つの場所で • 一つのページを一つのオブジェクトとして 扱い、カプセル化 • メソッドは実行する機能を表現する(DOM の操作ではない) http://memolog.org/2010/11/page_objects.php http://code.google.com/p/selenium/wiki/PageObjects わんくま同盟 大阪勉強会 #48
  • 27.
    [TestFixture] public class カプセル化{ [Test] public void 検索() { var driver = new InternetExplorerDriver(); try { var instance = BingSearch.Create(driver); instance.Input検索条件("Microsoft"); instance.Submit検索(); instance.Get検索結果件数().Is("527,000,000"); } finally { driver.Quit(); } } } わんくま同盟 大阪勉強会 #48
  • 28.
    public class BingSearch{ public static BingSearch Create(RemoteWebDriver driver) { var instance = new BingSearch(driver); driver.Url = "http://www.bing.com"; return instance; } private readonly RemoteWebDriver driver; private BingSearch(RemoteWebDriver driver) { this.driver = driver; } private IWebElement txt条件 { get { return driver.FindElementByName("q"); } } private IWebElement lbl件数 { get { return driver.FindElementById("count"); } } わんくま同盟 大阪勉強会 #48
  • 29.
    public void Input検索条件(string条件) { this.txt条件.Clear(); this.txt条件.SendKeys(条件); } public void Submit検索() { this.txt条件.Submit(); var wait = new WebDriverWait(this.driver, new TimeSpan(0, 0, 10)); wait.Until(ExpectedConditions.TitleIs( "Microsoft - Bing")); } public string Get検索結果件数() { return Regex.Match(this.lbl件数.Text, "(?<=of ).*(?= results)").Value; } } わんくま同盟 大阪勉強会 #48
  • 30.
    Java (Maven) で •selenium-java <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>2.20.0</version> </dependency> • ie-driver や support もついてくる わんくま同盟 大阪勉強会 #48
  • 31.
    @Test public void 検索(){ RemoteWebDriver driver = new InternetExplorerDriver(); try { driver.navigate().to("http://www.bing.com"); WebElement txt条件 = driver.findElementByName("q"); txt条件.sendKeys("Microsoft"); txt条件.submit(); Wait<WebDriver> wait = new WebDriverWait(driver, 10); wait.until(titleIs("Microsoft - Bing")); WebElement lbl件数 = driver.findElementById("count"); assertThat(lbl件数.getText().replaceAll( "(.*of )(.*)( results)", "$2"), is("527,000,000")); } finally { driver.quit(); } } わんくま同盟 大阪勉強会 #48
  • 32.
    @Test public void カプセル化(){ RemoteWebDriver driver = new InternetExplorerDriver(); try { BingSearch instance = BingSearch.create(driver); instance.input検索条件("Microsoft"); instance.submit検索(); assertThat(instance.get検索結果件数(), is("527,000,000")); } finally { driver.quit(); } } わんくま同盟 大阪勉強会 #48
  • 33.
    public class BingSearch{ private final RemoteWebDriver driver; public static BingSearch create(RemoteWebDriver driver) { BingSearch instance = new BingSearch(driver); driver.navigate().to("http://www.bing.com"); return instance; } private BingSearch(RemoteWebDriver driver) { this.driver = driver; } private WebElement txt条件() { return driver.findElementByName("q"); } private WebElement lbl件数() { return driver.findElementById("count"); } わんくま同盟 大阪勉強会 #48
  • 34.
    public void input検索条件(String条件) { this.txt条件().clear(); this.txt条件().sendKeys(条件); } public void submit検索() { this.txt条件().submit(); Wait<WebDriver> wait = new WebDriverWait(driver, 10); wait.until(titleIs("Microsoft - Bing")); } public String get検索結果件数() { return this.lbl件数().getText().replaceAll( "(.*of )(.*)( results)", "$2"); } } Java だとプロパティ(getter) の 括弧 が鬱陶しい! わんくま同盟 大阪勉強会 #48
  • 35.
    便利なやつ (その2) • PageFactory – PageObject の実装を少し楽にしてくれる – アノテーション/属性 ベースで、要素とフィー ルドのマッピング • WebElement 型の フィールド – キャッシュも可能 • ページ遷移/リロードを行った場合は、キャッシュ を取り直す必要あり – PageFactory.initElements で初期化を行う わんくま同盟 大阪勉強会 #48
  • 36.
    public class Top{ public static Top create(WebDriver driver) { driver.navigate().to("http://www.bing.com"); Top instance = new Top(driver); PageFactory.initElements(driver, instance); return instance; } private final WebDriver driver; private Top(WebDriver driver) { this.driver = driver; } @FindBy(name = "q") @CacheLookup private WebElement txt条件; わんくま同盟 大阪勉強会 #48
  • 37.
    public Result search(String条件) { this.txt条件.clear(); this.txt条件.sendKeys(条件); this.txt条件.submit(); Wait<WebDriver> wait = new WebDriverWait(driver, 10); wait.until(titleIs(条件 + " - Bing")); return Result.create(driver); } } わんくま同盟 大阪勉強会 #48
  • 38.
    public class Result{ public static Result create(WebDriver driver) { return PageFactory.initElements(driver, Result.class); } private final WebDriver driver; public Result(WebDriver driver) { this.driver = driver; } @FindBy(id="count") private WebElement lbl件数; public String 検索結果件数() { return lbl件数.getText() .replaceAll("(.*of )(.*)( results)", "$2"); } } わんくま同盟 大阪勉強会 #48
  • 39.
    便利なやつ(その3) • Select – input type=“select” な WebElement のラッ パー – Option の選択や取得を容易にしてくれる – PageFactory には対応していない わんくま同盟 大阪勉強会 #48
  • 40.
    Select WebElement select =~; List<WebElement> options = select.findElements(By.tagName("option")); for (WebElement option : options) { option.click(); // 選択させる if (option.isSelected()) { // 選択していたら } } Select wrapper = new Select(select); // 選択させる wrapper.selectByIndex(0); wrapper.selectByValue("hoge"); wrapper.selectByVisibleText("フヒヒ"); // 選択されているもの取得 wrapper.getFirstSelectedOption(); wrapper.getAllSelectedOptions(); わんくま同盟 大阪勉強会 #48
  • 41.
    よく使いそうな操作 • Table 表示のデータ取得 • スクリーンショットの取得 • input type=“file” へのパス指定 • Alert/Confirm ダイアログ • 新しい Window わんくま同盟 大阪勉強会 #48
  • 42.
    Table 表示のデータ取得 • Javaだとこんな感じ… – 1行を表すデータ型作成 – <tr> 単位でループし、コレクションの取得 • PageFactory 等を使用しインスタンス生成 – 比較処理 • .NET だと… わんくま同盟 大阪勉強会 #48
  • 43.
    [Test] public void Table(){ var driver = new ChromeDriver(@"c:work"); try { driver.Url = "http://nabewebdriver.apphb.com/"; var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10)); wait.Until(d => d.Title == "メニュー"); driver.FindElementByPartialLinkText("検索画面").Click(); wait.Until(d => d.Title == "Search"); driver.FindElementByXPath("//input[@type='submit' and @value='検索']").Click(); wait.Until(ExpectedConditions.ElementIsVisible(By.Id("results"))); driver.FindElementsById("roop").Select(e => new { Name = e.FindElement(By.Id("resultName")).Text, Birthday = e.FindElement(By.Id("resultBirthday")).Text, Money = e.FindElement(By.Id("resultMoney")).Text }).Is( new { Name = "名前1", Birthday = "1970/12/04", Money = "10,000" }, new { Name = "名前2", Birthday = "1980/10/15", Money = "15,000" }, new { Name = "名前3", Birthday = "1979/06/23", Money = "20,000" }, new { Name = "名前4", Birthday = "1990/08/06", Money = "25,000" }, new { Name = "名前5", Birthday = "2000/07/04", Money = "30,000" } ); } finally { driver.Quit(); } } わんくま同盟 大阪勉強会 #48
  • 44.
    driver.FindElementsById("roop").Select(e => new{ Name = e.FindElement(By.Id("resultName")).Text, Birthday = e.FindElement(By.Id("resultBirthday")).Text, Money = e.FindElement(By.Id("resultMoney")).Text }).Is( new { Name = "名前1", Birthday = "1970/12/04", Money = "10,000" }, new { Name = "名前2", Birthday = "1980/10/15", Money = "15,000" }, new { Name = "名前3", Birthday = "1979/06/23", Money = "20,000" }, new { Name = "名前4", Birthday = "1990/08/06", Money = "25,000" }, new { Name = "名前5", Birthday = "2000/07/04", Money = "30,000" } ); わんくま同盟 大阪勉強会 #48
  • 45.
    スクリーンショットの取得 • TakesScreenshot を実装しているDriver が対象 – 殆どの Driver は実装している • Java だと… FileUtils.copyFile( driver.getScreenshotAs(OutputType.FILE), new File("c:/work/hoge.png") ); • NET だと… driver.GetScreenshot().SaveAsFile( @"c:workhoge.png", ImageFormat.Png); わんくま同盟 大阪勉強会 #48
  • 46.
    input type=“file” へのパス指定 •WebElement を取得し、sendKeys でフル パスを渡す。 • Java だと… driver.findElement(By.id("fileupload")) .sendKeys("c:/work/result.jpg"); • NET だと… driver.FindElement(By.Id("fileupload")) .SendKeys(@"c:workresult.jpg"); わんくま同盟 大阪勉強会 #48
  • 47.
    Alert/Confirm ダイアログ • WebDriverから TargetLocator を取得し、 alert を呼ぶ。 • Java だと… Alert dialog = driver.switchTo().alert(); • NET だと… var dialog = driver.SwitchTo().Alert(); わんくま同盟 大阪勉強会 #48
  • 48.
    Alert インターフェース • getText – 表示しているテキストを取得 • accept – OK ボタンクリック • dismiss – キャンセル ボタンクリック • sendKeys わんくま同盟 大阪勉強会 #48
  • 49.
    Alert/Confirm ダイアログ 注意点 •ダイアログが表示されている間は他の操作 は出来ない – Driver や Element の操作 • accept/dismiss した後に Alert を操作 – 閉じている Dialog は操作出来ない • Alert を取得する際は、念のため Wait を使 う わんくま同盟 大阪勉強会 #48
  • 50.
    エラーになるケース HTML <input type="button" id="btn"value="hoge“ onclick="alert('hoge');" /> <input type="text" id="txt" /> C# コード var text = driver.FindElementById("txt"); driver.FindElementById("btn").Click(); // text.SendKeys("hoge"); // Error // driver.FindElementById("button"); // Error var dialog = driver.SwitchTo().Alert(); dialog.Accept(); var dialogText = dialog.Text; // Error わんくま同盟 大阪勉強会 #48
  • 51.
    Alert 取得時の Wait •Java だと… Wait<WebDriver> wait = new WebDriverWait(driver, 10); Alert dialog = wait.until(alertIsPresent()); • NET だと… var wait = new WebDriverWait( driver, new TimeSpan(0, 0, 10)); var dialog = wait.Until(d => { try { return d.SwitchTo().Alert(); } catch (Exception) { return null;} }); わんくま同盟 大阪勉強会 #48
  • 52.
    新しい Window • WebDriverから TargetLocator を取得し、 window を呼ぶ。 – 戻り値は WebDriver で呼び出し元と同じイン スタンス • Java だと… driver.switchTo().window("name or handler"); • NET だと… driver.SwitchTo().Window("name"); // 一応 handler でもOK わんくま同盟 大阪勉強会 #48
  • 53.
    WindowHandler の取得 • Javaだと… String current = driver.getWindowHandle(); Set<String> all = driver.getWindowHandles(); • NET だと… var current = driver.CurrentWindowHandle; var all = driver.WindowHandles; わんくま同盟 大阪勉強会 #48
  • 54.
    新しい Window 切替時のWait • Java だと… Wait<WebDriver> wait = new WebDriverWait(driver, 10); wait.until(new Function<WebDriver, WebDriver>() { public WebDriver apply(WebDriver arg0) { try { return arg0.switchTo().window("windowName"); } catch (Exception e) { return null; } } }); • NET だと… var wait = new WebDriverWait( driver, new TimeSpan(0, 0, 10)); wait.Until(d => { try { return d.SwitchTo().Window("windowName"); } catch (Exception) { return null;} }); わんくま同盟 大阪勉強会 #48
  • 55.
  • 56.
    まとめ • 複数の言語/ブラウザに対応している –Java が API が充実してそう • 大概のことは出来ます – 今回説明省いたきましたが、Interactions を使 えば、Drag&Drop みたいな事も http://code.google.com/p/selenium/wiki/AdvancedUserInteractions# Mouse_interactions • Wait 超大事! • 当然テスト以外でも使えます – ブラウザ操作の自動化 わんくま同盟 大阪勉強会 #48