自己紹介
みなさんに質問です
自動テストしてますか?
アジェンダ
始める前に
管理者に許可をとってやろうね!
- 息の根止めることがあるので...
- 威力業務妨害になることも...
今日はテスト用のアプリを用意してます!
存分に遊びましょう!
公式サイトが Google を使ってるのはいいんだろうか?
Selenium とは?
Selenium とは?
Selenium automates browsers. That's it!
Selenium は自動でブラウザーを操作します。それがすべてです!
(公式サイトより)
やってみる
// Firefox を使う
var driver = new FirefoxDriver();
// URL を設定
driver.Url = "https://www.google.com";
// 検索ボックスに "Selenium" を入力
var query = driver.FindElement(By.Name("q"));
query.SendKeys("Selenium");
// 検索を開始
query.Submit();
// 検索結果が表示されるまで待つ (最大 10 秒)
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.Title.StartsWith("Selenium", StringComparison.OrdinalIgnoreCase));
// 検索結果を表示する
var result = driver.FindElements(By.ClassName("r"));
foreach (var line in result)
Console.WriteLine(line.Text);
結果
どこで使う?
- 一番は UI オートメーションテスト用
- ブラウザーアプリのフォーム投稿の自動化
- スクリーンショットの撮影
Selenium の話の前に
製品群がややこしい
- Selenium 1 or 2?
- Selenium WebDriver
- Selenium Grid
- Selenium IDE
- Selenium Remote Control (RC)
製品群がややこしい
- 今日の主題は Selenium WebDriver です
- Selenium IDE/RC は古いので無視な方向で
- 検索すると古い情報なこともあるから要注意
Selenium 解説
必要なもの
- ブラウザー
- WebDriver - ブラウザーを操作するプログラム
- 言語バインディング - プログラムから Selenium を呼び出すライブラリ
- Selenium Server - とりあえず使うだけなら不要 (要 Java)
WebDriver
- 基本、ブラウザーメーカーが提供
- ダウンロードして、パスの通った場所にコピー
- 非公式でスマフォやデスクトップアプリ向けもある
言語バインディング
- nuget や pip や npm や maven や gem でダウンロードできる
- 非公式でわんさかある
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com");
WebElement query = driver.FindElement(By.name("q"));
var driver = new FirefoxDriver();
driver.Url = "http://www.google.com";
var query = driver.FindElement(By.Name("q"));
driver = webdriver.Firefox()
driver.get("https://www.google.com")
query = driver.find_element(By.NAME, "q")
var driver = new webdriver.Builder().build();
driver.get('http://www.google.com');
var query = driver.findElement(webdriver.By.name('q'));
初期化
var driver = new FirefoxDriver();
driver.Url = "https://www.google.com";
driver = webdriver.Chrome()
driver.get("https://www.google.com")
なんちゃら Driver を作成して、URL をセット!
要素の選択
var query = driver.FindElement(By.Name("q"));
query = driver.find_element(By.NAME, "q")
Chrome DevTools などで要素を探す
<tagname>
から </tagname>
までが要素
<div>
<h1>Hoge</h1>
</div>
<input type="text" name="foo">
-
div
要素とh1
要素とinput
要素がある -
input
要素のように閉じタグが不要なものもある
<input type="text" name="p1">
~~~~~~~~~~~
type 属性
<!-- name 属性は特殊 -->
<!-- テキストボックスやチェックボックスやボタンでよく使う -->
<input type="text" name="p1">
~~~~~~~~~
p1 が名前
<!-- class 属性は主に CSS から使う -->
<!-- 要素を分類する -->
<h1 class="title main">Hoge</title>
~~~~~~~~~~~~~~~~~~
この要素のクラスは title と main の二つ
<!-- id 属性は要素を特定するのに使い、ページ内で必ず一意 -->
<button id="show-button" type="button">Show</button>
~~~~~~~~~~~~~~~~
show-button という ID の要素
By Link Text
リンクのテキストが一致する要素
var element = driver.FindElement(By.LinkText("Save"));
element = driver.find_element(By.LINK_TEXT, "Save");
<a href="#">Save</a> <!-- これは OK -->
<a href="#">Save!</a> <!-- これは NG -->
-
By.PartialLinkText
部分マッチもあるよ
By ID
ID が一致する要素
var element = driver.FindElement(By.ID("save"));
element = driver.find_element(By.ID, "save");
<a id="save" href="#">Save</a> <!-- これは OK -->
<a id="save2" href="#">Save!</a> <!-- これは NG -->
By Name
名前が一致する要素
var element = driver.FindElement(By.Name("password"));
element = driver.find_element(By.NAME, "password");
<input type="password" name="password"> <!-- これは OK -->
<input type="password" name="password2"> <!-- これは NG -->
By Class Name
class が一致する要素
var element = driver.FindElement(By.ClassName("email"));
element = driver.find_element(By.CLASS_NAME, "email");
<input name="email" class="email"> <!-- これは OK -->
<input name="email" class="email input"> <!-- これも OK -->
<input name="email" class="email2 input"> <!-- これは NG -->
By CSS
CSS Selector っぽい書き方ができる
// var element1 = driver.FindElement(By.ID("save"));
var element1 = driver.FindElement(By.CssSelector("#save"));
// var element2 = driver.FindElement(By.Name("password"));
var element2 = driver.FindElement(By.CssSelector("[name=\"password\"]"));
// var element3 = driver.FindElement(By.ClassName("email"));
var element3 = driver.FindElement(By.CssSelector(".email"));
var element = driver.FindElement(By.CssSelector(".header .title"));
どれを使えばよいの?
-
By.ID
以外は予想外の要素が選択されることも - 頑張りたい人の
By.LinkText
- (個人的には)
By.CssSelector
一択-
By.CssSelector(".user-register-form .username")
と書くのが好き
-
var element = driver.FindElement(By.LinkText("Address"));
<article>
記事...
</article>
<footer>
<a href="#">Address</a>
</footer>
記事が変わると予想外のことろが反応する
<article>
<a href="#">Address</a>とは日本語で住所のこと...
</article>
<footer>
<a href="#">Address</a>
</footer>
FindElement/FindElements
-
FindElement
は先頭の要素を一つ取得する -
FindElement
は要素が無ければ例外を投げる -
FindElements
はすべての要素を取得する
こんな感じフォーム内のパスワードテキストボックスという書き方もできる
var form = driver.FindElement(By.CssSelector("form"));
var password = form.FindElement(By.CssSelector(".password"));
操作
よく使うもの
-
SendKeys
- 要素にフォーカスを移動してキーボード入力 -
Clear
- 要素にフォーカスを移動してテキストボックスをクリア -
Click
- 要素の位置をマウスクリック -
Submit
- サブミット - そのほか、ドラッグとかいろいろできる
var username = driver.FindElement(By.ID("username"));
username.Clear(); // 保険
username.SendKeys("masakura"); // テキストボックスへの入力
username.Submit(); // 投稿
username = driver.find_element(By.ID, "username");
username.clear();
username.sendKeys("masakura");
username.submit();
情報の取得
-
Text
- 表示されているテキストを取得 -
GetAttribute("value")
-value
属性値を取得
// <span id="username">masakura</span>
var username = driver.FindElement(By.ID("username"));
var text = username.Text; // テキストを取得
username = driver.find_element(By.ID, "username");
text = username.text;
// <input id="username">
var username = driver.FindElement(By.ID("username"));
var text = username.GetAttribute("value"); // 入力値を取得
username = driver.find_element(By.ID, "username");
text = username.get_attribute("value");
後始末
必ず Quit()
を呼び出す
using (var driver = new FirefoxDriver()) {
// 処理
} // ここで driver.Quit() が呼ばれる
driver = webdriver.Firefox()
try:
# 処理
finally:
driver.quit()
リファレンスを!
だいたいリファレンスに書いてある
テスト
テスト機能は範囲外
- Selenium WebDriver はテスト機能はもたない
- テストは各言語のテスティングフレームワークと組み合わせる
- テストでは以下のものが最低限必要
- ブラウザー (Firefox, Chrome, etc...)
- WebDriver (geckodriver, chromedriver, etc...)
- 言語バインディング
- テスティングフレームワーク (JUnit, xUnit, Cucumber, etc...)
テストコード (xUnit.NET)
public class Test
{
[Fact]
public void SuccessTest()
{
var result = MyCalc.Add(1, 1);
Assert.Equal(2, result);
}
[Fact]
public void FailTest()
{
var result = MyCalc.Add(1, 1);
Assert.Equal(3, result);
// ~~~~~~~~~~~~~~~~~~~~~~~
// 値が等しいことを検査するアサーション
// 等しくなければテスト失敗
}
}
テストコード (Python)
import unittest
class Test(unittest.TestCase):
def test_success(self):
result = my_calc.add(1, 1);
self.assertEqual(2, result)
def test_failself):
result = my_calc.add(1, 1);
self.assertEqual(3, result)
テスト (Selenium あり)
Selenium ありだとこんな感じ
public class Test
{
[Fact]
public void TitleTest()
{
using (var driver = new FirefoxDriver())
{
driver.Url = "https://www.google.com";
Assert.Equal(driver.Title, "Google");
}
}
}
細かいことはググりましょう!
Selenium WebDriver の動作モード
三種類ある
- 一番単純なモード (名前が分からない...)
- Standalone モード
- Selenium Grid モード
一番単純なモード
- Java が不要
Standalone モード
- 他のマシンに接続できる
// ブラウザーを指定する
var capabilities = new DesireCapabilities();
capablities.SetCapability("browserName", "firefox");
// FirefoxDriver の代わりに RemoteWebDriver を使う
var drivier = new RemoteWebDriver("http://standalone.example.com:4444/wd/hub", capabilities);
Selenium Grid モード
お題目
- まずは遊んでみよう!
- ウェブアプリをテストしよう!
- Selenium Grid を使ってみよう!
- Selenium Grid を構築してみよう!
- PageObject パターンを使ってみよう!
- Appium を使ってみよう!
セットアップ
- ブラウザーをインストール
- Firefox, Chrome がいいかも
- 対応するブラウザーの WebDriver をインストール
- http://docs.seleniumhq.org/download/#thirdPartyDrivers
- 解凍してパスの通った場所にコピー
- わからない人は周りに聞いてみよう!
テストサイト
- https://tukuddo01.azurewebsites.net
- tukuddo01 - tukuddo15 まであるよ!
まずは遊んでみよう!
ブラウザーの自動操作をするだけ!
Python
コマンドプロンプトで...
> mkdir seleniumtest
> cd seleniumtest
> python -m venv venv
> venv\Scripts\activate
> pip install selenium
> python
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017,Type "help", "copyright", "credits" or "license" for more information.
>>>
ターミナルで...
$ mkdir seleniumtest
$ cd seleniumtest
$ python -m venv venv
$ ./venv/bin/activate
$ pip install selenium
$ python
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017,Type "help", "copyright", "credits" or "license" for more information.
>>>
Python
下準備
>>> from selenium import webdriver
>>> from selenium.webdriver.common.by import By
>>> from selenium.webdriver.support.wait import WebDriverWait
>>> from selenium.webdriver.support import expected_conditions as EC
>>> driver = webdriver.Firefox()
driver = webdriver.Firefox()
でブラウザーが起動する
Python
操作する!
>>> driver.get("https://tukuddo01.azurewebsites.net")
>>> link = driver.find_element(By.LINK_TEXT, "Sign in / Register")
>>> link.click()
>>> form = driver.find_element(By.CLASS_NAME, "signin-input")
>>> username = form.find_element(By.CLASS_NAME, "username")
>>> username.send_keys("hogehoge")
>>> password = form.find_element(By.CLASS_NAME, "password")
>>> password.send_keys("password")
>>> signin = form.find_element(By.CLASS_NAME, "signin")
>>> signin.click()
Python
いろいろ試してみよう!
WebdriverIO (Node.js)
- Selenium WebDriver の Node.js 用ラッパー
- 公式ではないけど、こちらの方が使いやすい
- JavaScript ではこういうラッパーライブラリをよく使う
WebdriverIO (Node.js)
下準備
$ mkdir seleniumtest
$ cd seleniumtest
$ npm install selenium-standalone webdriverio wdio-sync
$ ./node_modules/.bin/selenium-standalone install
WebdriverIO (Node.js)
Selenium Standalone Server 起動
$ ./node_modules/.bin/selenium_standalone start
WebdriverIO (Node.js)
操作する!
$ ./node_modules/.bin/wdio repl firefox
> browser.url("https://tukuddo01.azurewebsites.net")
> el = $('.menu-item.signin')
> el.click()
ウェブアプリをテストしよう!
- 細かいことは考えずに、テストしてみよう!
- 慣れてる人は、テストを細かくしてみよう!
Selenium Grid を使ってみよう!
- Selenium Grid を一台用意してます
- Edge/Firefox/Chrome (Windows)
- Firefox/Chrome (Linux)
- http://192.168.10.11:4444/grid/console - コンソール
- http://192.168.10.11:4444/wd/hub
--
Selenium Grid を構築してみよう!
- Docker 版を使う手も
- 高橋さんが LT するよ!
PageObject パターンを使ってみよう!
テストパターンが増えてくるといろいろと厄介
// 標準
driver.FindElement(By.ID("input-title")).SendKeys("たいとる");
driver.FindElement(By.ID("input-desc")).SendKeys("本文");
driver.FindElement(By.ID("input-submit")).Click();
// タイトルなし
driver.FindElement(By.ID("input-title")).SendKeys("");
driver.FindElement(By.ID("input-desc")).SendKeys("本文");
driver.FindElement(By.ID("input-submit")).Click();
// 本文なし
driver.FindElement(By.ID("input-title")).SendKeys("たいとる");
driver.FindElement(By.ID("input-desc")).SendKeys("");
driver.FindElement(By.ID("input-submit")).Click();
// 長いタイトル
driver.FindElement(By.ID("input-title")).SendKeys(LongText(256));
driver.FindElement(By.ID("input-desc")).SendKeys("本文");
driver.FindElement(By.ID("input-submit")).Click();
input-title
が変更されても追従しやすいように
// 標準
page.Submit(new {Title = "たいとる", Desc = "本文");
// タイトルなし
page.Submit(new {Title = "", Desc = "本文");
// 本文なし
page.Submit(new {Title = "たいとる", Desc = "");
// 長いタイトル
page.Submit(new {Title = LongText(256), Desc = "本文");
Appium を使ってみよう!
こういうのがテストできる
- Android/iOS のブラウザー
- Android/iOS のネイティブアプリ
こっそり、Selenium Grid に追加してあります