【CAMPHOR- × サイボウズ】
Selenium 勉強会
2014/12/14 CAMPHOR- HOUSE
ハッシュタグ #cybozu
自己紹介
• 岡田勇樹 @y_okady
• サイボウズ新卒8年目 31歳
• 神戸大学大学院 情報知能工学専攻
• kintone開発チーム リーダー
• 大阪開発部@グランフロント 副部長
Agenda
• サイボウズとkintoneのご紹介
• Seleniumの解説
• Seleniumハンズオン
• 自動テストでSeleniumを使うために必要なこと
• 最後に
サイボウズとkintone
サイボウズ
• 「グループウェア」のメーカー
• 東京、松山、大阪、上海、ベトナムで開発
• バリバリ開発してる会社
• どんなものを作るか考えるのも実際に作るのも全部内製
• インフラからWebアプリケーションまで全部内製
• 特徴的な人事制度
• 会社辞めてもいつでも戻ってきていいよ
• 台風の日はできるだけ在宅勤務してね
• 国内シェアNo.1、kintoneで世界一を目指してます
kintone
業務アプリ?Webデータベー
ス?
こんな時どうする
• チームでアイデアを共有する「アイデアボッ
クス」を作りたい時、あなたならどうします
か?
アイデアボックスを作ろう
• やっぱWebアプリでしょ
• サーバー用意しなきゃ
• 言語とかフレームワークとかどうしよっかな
• データベースの設計しなきゃ
• 何日あれば作れるかな…
kintoneの場合
そろそろSeleniumの話が聞きたいなー
実はもう始まってます
実はさっきの動画
• kintoneをSeleniumで操作したんです!
• テキストボックスへの入力も
• ラジオボタンの選択も
• リンクのクリックも
• ドラッグ&ドロップも
• Seleniumってなんかすごそう!!
Selenium
Seleniumとは
• Webブラウザの操作を自動化するツール
• Firefox拡張のSelenium IDEが一世を風靡
• プログラミング不要
• UIを変更するとテストがすぐ落ちる
• Firefoxでしか動かない
• 近年Selenium WebDriverが頭角を現す
Seleniumでできること
• URLを指定してWebページを開く
• DOMの要素を取得する
• 要素に対して何かする
• クリックする
• 文字を取り出す
• 文字を入力する
• ドラッグ&ドロップする
Selenium WebDriver
JavaScript
ブラウザ/OS API
昔のSelenium
Selenium
WebDriver
言語バインディング
• 公式
• 非公式
ハンズオン
ハンズオンの流れ
1.インストール
2.動作確認
3.CAMPHOR-のWebサイトを操作
4.Google検索ページを操作
Seleniumのインストール
• Python
• Ruby
• JavaScript (Node.js)
• Java
$ pip install selenium
$ gem install selenium-webdriver
$ npm install -g selenium-webdriver
$ curl -O http://selenium-release.storage.googleapis.com/2.44/selenium-
java-2.44.0.zip && unzip selenium-java-2.44.0.zip
http://www.seleniumhq.org/
Driverのダウンロード
• Chrome (Mac)
• Chrome (Windows)
• Firefoxは不要
$ curl -O http://chromedriver.storage.googleapis.com/2.12/
chromedriver_mac32.zip && unzip chromedriver_mac32.zip
$ curl -O http://chromedriver.storage.googleapis.com/2.12/
chromedriver_win32.zip && unzip chromedriver_win32.zip
動作確認
• サイボウズのWebサイトを開いてみよう
• 処理の流れ
• Seleniumをimport/require
• Firefox/Chrome Driverインスタンスを生成
• getメソッドにURLを指定してWebサイトを開く
• quitメソッドで終了
http://cybozu.co.jp
動作確認
• 本家ドキュメント
• 処理の流れ
• Seleniumをimport/require
• Firefox/Chrome Driverインスタンスを生成
• getメソッドにURL (http://cybozu.co.jp) を指定
• quitメソッドで終了
[Documentation] > [Introducing the Selenium-WebDriver API by Example]
http://www.seleniumhq.org/
Programming Language Preference を選択
サンプルコード (Python)
from selenium import webdriver!
!
driver = webdriver.Firefox()!
#driver = webdriver.Chrome('./chromedriver')!
!
driver.get("http://cybozu.co.jp")!
driver.quit()
$ python 1.py
サンプルコード (Ruby)
require 'selenium-webdriver'!
!
driver = Selenium::WebDriver.for :firefox!
#driver = Selenium::WebDriver.for :chrome!
!
driver.get “http://cybozu.co.jp”!
driver.quit
$ ruby 1.rb
サンプルコード (JavaScript)
var firefox = require('selenium-webdriver/firefox');!
//var chrome = require('selenium-webdriver/chrome');!
!
var driver = new firefox.Driver();!
//var driver = new chrome.Driver();!
!
driver.get('http://cybozu.co.jp');!
driver.quit();
$ node 1.js
サンプルコード (Java)
import org.openqa.selenium.WebDriver;!
import org.openqa.selenium.chrome.ChromeDriver;!
import org.openqa.selenium.firefox.FirefoxDriver;!
!
public class SeleniumIntro {!
public static void main(String[] args) {!
WebDriver driver = new FirefoxDriver();!
//WebDriver driver = new ChromeDriver();!
!
driver.get("http://cybozu.co.jp");!
driver.quit();!
}!
}
$ javac -cp selenium-2.44.0/selenium-java-2.44.0.jar Selenium1.java!
$ java -cp .:selenium-2.44.0/selenium-java-2.44.0.jar:selenium-2.44.0/libs/* Selenium1
CAMPHOR-のWebサイトを操作
• トップページ (https://camph.net) で
「CAMPHOR-について詳しく見る」をクリッ
クすると、About (https://camph.net/about/)
に遷移することを確認する
CAMPHOR-のWebサイトを操作
• WebDriver APIドキュメント
• Python: http://selenium-python.readthedocs.org/en/latest/api.html
• Ruby: http://www.rubydoc.info/gems/selenium-webdriver/0.0.28/Selenium/
WebDriver
• JavaScript: http://selenium.googlecode.com/git/docs/api/javascript/
module_selenium-webdriver.html
• Java: https://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/
selenium/WebDriver.html
• 処理の流れ
• driver.findElementとBy.linkTextでリンク要素を取得
• リンク要素をクリック
サンプルコード (Python)
# -*- coding: utf-8 -*-!
from selenium import webdriver!
from selenium.webdriver.common.by import By!
!
driver = webdriver.Firefox()!
#driver = webdriver.Chrome('./chromedriver')!
!
driver.get("https://camph.net")!
!
link = driver.find_element(By.LINK_TEXT, u"CAMPHOR-について詳しく見る");!
link.click()!
!
print driver.current_url == "https://camph.net/about/"!
!
driver.quit()
サンプルコード (Ruby)
require 'selenium-webdriver'!
!
driver = Selenium::WebDriver.for :firefox!
#driver = Selenium::WebDriver.for :chrome!
!
driver.get "https://camph.net"!
!
link = driver.find_element(:link_text, "CAMPHOR-について詳しく見る")!
link.click!
!
print driver.current_url == "https://camph.net/about/"!
!
driver.quit
サンプルコード (JavaScript)
var By = require('selenium-webdriver').By;!
var firefox = require('selenium-webdriver/firefox');!
//var chrome = require('selenium-webdriver/chrome');!
!
var driver = new firefox.Driver();!
//var driver = new chrome.Driver();!
!
driver.get('https://camph.net');!
!
var link = driver.findElement(By.linkText('CAMPHOR-について詳しく見る'));!
link.click();!
!
driver.getCurrentUrl().then(function(url) {!
console.log(url == 'https://camph.net/about/');!
});!
!
driver.quit();
サンプルコード (Java)
import org.openqa.selenium.By;!
import org.openqa.selenium.WebDriver;!
import org.openqa.selenium.WebElement;!
import org.openqa.selenium.chrome.ChromeDriver;!
import org.openqa.selenium.firefox.FirefoxDriver;!
!
public class Selenium2 {!
public static void main(String[] args) {!
WebDriver driver = new FirefoxDriver();!
//WebDriver driver = new ChromeDriver();!
!
driver.get("https://camph.net");!
!
WebElement link = driver.findElement(By.linkText("CAMPHOR-について詳しく見る"));!
link.click();!
!
System.out.println(driver.getCurrentUrl().equals("https://camph.net/about/"));!
!
driver.quit();!
}!
}
Google検索ページを操作
• 「サイボウズ」を検索した時に表示される、関連キーワード
一覧を出力する
• 処理の流れ
• 検索ボックスに「サイボウズ」を入力
• フォームをsubmit
• 検索結果画面が表示されるまで待つ
• 関連キーワードの要素からリンク一覧を取得
サンプルコード (Python)
# -*- coding: utf-8 -*-!
from selenium import webdriver!
from selenium.webdriver.common.by import By!
from selenium.webdriver.support.ui import WebDriverWait!
from selenium.webdriver.support import expected_conditions!
!
driver = webdriver.Firefox()!
#driver = webdriver.Chrome('./chromedriver')!
!
driver.get("http://www.google.com")!
!
input = driver.find_element(By.NAME, "q")!
input.send_keys(u"サイボウズ")!
input.submit()!
!
WebDriverWait(driver, 10).until(expected_conditions.title_is(u”サイボウズ - Google 検索"))!
!
extra = driver.find_element(By.ID, "extrares")!
links = extra.find_elements(By.TAG_NAME, "a")!
for link in links:!
print link.text!
!
driver.quit()
サンプルコード (Ruby)
require 'selenium-webdriver'!
!
driver = Selenium::WebDriver.for :firefox!
#driver = Selenium::WebDriver.for :chrome!
!
driver.get "http://www.google.com"!
!
input = driver.find_element(:name, "q")!
input.send_keys("サイボウズ")!
input.submit()!
!
wait = Selenium::WebDriver::Wait.new(:timeout => 10)!
wait.until {!
driver.title == “サイボウズ - Google 検索“!
}!
extra = driver.find_element(:id, "extrares")!
links = extra.find_elements(:tag_name, "a")!
links.each {|link|!
puts link.text!
}!
!
driver.quit
サンプルコード (JavaScript)
var By = require('selenium-webdriver').By;!
var firefox = require('selenium-webdriver/firefox');!
//var chrome = require('selenium-webdriver/chrome');!
!
var driver = new firefox.Driver();!
//var driver = new chrome.Driver();!
!
driver.get('http://www.google.com');!
var input = driver.findElement(By.name('q'));!
input.sendKeys('サイボウズ');!
input.submit();!
!
driver.wait(function() {!
return driver.getTitle().then(function(title) {!
return title == ‘サイボウズ - Google 検索‘;!
});!
}, 10000);!
var extra = driver.findElement(By.id('extrares'));!
extra.findElements(By.tagName('a')).then(function(links) {!
for (var i = 0; i < links.length; i++) {!
links[i].getText().then(function(text) {!
console.log(text);!
});!
}!
});!
!
driver.quit();
サンプルコード (Java)
import java.util.List;!
import org.openqa.selenium.By;!
import org.openqa.selenium.WebDriver;!
import org.openqa.selenium.WebElement;!
import org.openqa.selenium.chrome.ChromeDriver;!
import org.openqa.selenium.firefox.FirefoxDriver;!
import org.openqa.selenium.support.ui.ExpectedCondition;!
import org.openqa.selenium.support.ui.WebDriverWait;!
!
public class Selenium3 {!
public static void main(String[] args) {!
WebDriver driver = new FirefoxDriver();!
//WebDriver driver = new ChromeDriver();!
!
driver.get("http://google.com");!
!
WebElement input = driver.findElement(By.name("q"));!
input.sendKeys("サイボウズ");!
input.submit();!
!
(new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {!
public Boolean apply(WebDriver d) {!
return d.getTitle().equals("サイボウズ - Google 検索");!
}!
});!
!
WebElement extra = driver.findElement(By.id("extrares"));!
List<WebElement> links = extra.findElements(By.tagName("a"));!
for (WebElement link : links) {!
System.out.println(link.getText());!
}!
!
driver.quit();!
}!
}
Seleniumで自動テスト
テストフレームワーク
• xUnitなど
• 自動テストをやるなら必須
PageObjectデザインパターン
• テスト対象となる画面やコンポーネントを
PageObjectと呼ばれるクラスで共通化
• テストメソッド内にByを書かなくて済む
• UI変更に強くなる
• Seleniumテストをいっぱい書くなら必須
RemoteWebDriver
• テストを実行するマシンとブラウザを操作す
るマシンを分ける
• 複数のOSやブラウザでテストをするなら必須
Selenium Grid
• 複数のOSやブラウザでのテストを並列化する
• Seleniumテストをめっちゃいっぱい書くなら
必須
Jenkins
• 継続的インテグレーションツール
• Gitにpushされた時に自動的にSeleniumテス
トを実行したりできる
• 大人数で開発したり、より高い品質を求める
なら必須
kintoneとSelenium
• テストケースは1,000個以上
• 並列数は36
• 実行時間は約30分
• kintoneはSeleniumに支えられてます!
最後に
まだまだ伝えたいことがある!
• PageObjectパターンでUI変更に強いテストを書こう
• RemoteWebDriverを使っていろんなブラウザでテス
トしよう
• Selenium Gridを使って大規模運用しよう
• Jenkinsで自動テストを自動実行しよう
次回Selenium勉強会
• 今のところ未定!
• でもやりたい
• 発表者募集中です
• もちろん参加者募集中です
• こんなことやりたい!というのがあればアン
ケートに記入お願いします
本当に最後に
• サイボウズで一緒にSeleniumテストを書いてくれる仲間を募集中です!
• テスト自動化しておふくろを楽にしたい方
• テスト自動化して彼女を作りたい方
• テスト自動化して人生を豊かにしたい方
• 勉強会の出席を自動化したい方
• テスト自動化してモテたい方
• テスト自動化してみんなを幸せにしたい方
• 学校のテストでいい点取りたい方
ありがとうございました!
懇親会もよろしくお願いします!!

【Camphor ×サイボウズ】selenium勉強会