LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

Selenium でテスト

Last updated at Posted at 2018-02-10
1 / 84

自己紹介


みなさんに質問です


自動テストしてますか?


chart(2).png


chart(1).png


chart.png


アジェンダ


始める前に


管理者に許可をとってやろうね!

  • 息の根止めることがあるので...
  • 威力業務妨害になることも...

今日はテスト用のアプリを用意してます!


存分に遊びましょう!


公式サイトが Google を使ってるのはいいんだろうか?

image.png


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);

結果

image.png


どこで使う?

  • 一番は 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

image.png

  • 基本、ブラウザーメーカーが提供
  • ダウンロードして、パスの通った場所にコピー
  • 非公式でスマフォやデスクトップアプリ向けもある

言語バインディング

image.png

  • nuget や pip や npm や maven や gem でダウンロードできる
  • 非公式でわんさかある

Java
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com");
WebElement query = driver.FindElement(By.name("q"));
C#
var driver = new FirefoxDriver();
driver.Url = "http://www.google.com";
var query = driver.FindElement(By.Name("q"));
Python
driver = webdriver.Firefox()
driver.get("https://www.google.com")
query = driver.find_element(By.NAME, "q")
JavaScript(Node.js)
var driver = new webdriver.Builder().build();
driver.get('http://www.google.com');
var query = driver.findElement(webdriver.By.name('q'));

初期化

C#
var driver = new FirefoxDriver();

driver.Url = "https://www.google.com";
Python
driver = webdriver.Chrome()

driver.get("https://www.google.com")

なんちゃら Driver を作成して、URL をセット!


要素の選択

C#
var query = driver.FindElement(By.Name("q"));
Python
query = driver.find_element(By.NAME, "q")

Chrome DevTools などで要素を探す

image.png


<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

リンクのテキストが一致する要素

C#
var element = driver.FindElement(By.LinkText("Save"));
Python
element = driver.find_element(By.LINK_TEXT, "Save");
<a href="#">Save</a> <!-- これは OK -->
<a href="#">Save!</a> <!-- これは NG -->
  • By.PartialLinkText 部分マッチもあるよ

By ID

ID が一致する要素

C#
var element = driver.FindElement(By.ID("save"));
Python
element = driver.find_element(By.ID, "save");
<a id="save" href="#">Save</a> <!-- これは OK -->
<a id="save2" href="#">Save!</a> <!-- これは NG -->

By Name

名前が一致する要素

C#
var element = driver.FindElement(By.Name("password"));
Python
element = driver.find_element(By.NAME, "password");
<input type="password" name="password"> <!-- これは OK -->
<input type="password" name="password2"> <!-- これは NG -->

By Class Name

class が一致する要素

C#
var element = driver.FindElement(By.ClassName("email"));
Python
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 っぽい書き方ができる

C#
// 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") と書くのが好き

C#
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 はすべての要素を取得する

こんな感じフォーム内のパスワードテキストボックスという書き方もできる

C#
var form = driver.FindElement(By.CssSelector("form"));
var password = form.FindElement(By.CssSelector(".password"));

操作

よく使うもの

  • SendKeys - 要素にフォーカスを移動してキーボード入力
  • Clear - 要素にフォーカスを移動してテキストボックスをクリア
  • Click - 要素の位置をマウスクリック
  • Submit - サブミット
  • そのほか、ドラッグとかいろいろできる

C#
var username = driver.FindElement(By.ID("username"));

username.Clear(); // 保険
username.SendKeys("masakura"); // テキストボックスへの入力
username.Submit(); // 投稿
Python
username = driver.find_element(By.ID, "username");

username.clear();
username.sendKeys("masakura");
username.submit();

情報の取得

  • Text - 表示されているテキストを取得
  • GetAttribute("value") - value 属性値を取得

C#
// <span id="username">masakura</span>
var username = driver.FindElement(By.ID("username"));
var text = username.Text; // テキストを取得
Python
username = driver.find_element(By.ID, "username");
text = username.text;
C#
// <input id="username">
var username = driver.FindElement(By.ID("username"));
var text = username.GetAttribute("value"); // 入力値を取得
Python
username = driver.find_element(By.ID, "username");
text = username.get_attribute("value");

後始末

必ず Quit() を呼び出す

C#
using (var driver = new FirefoxDriver()) {
    // 処理
} // ここで driver.Quit() が呼ばれる
Python
driver = webdriver.Firefox()

try:
    # 処理
finally:
    driver.quit()

リファレンスを!

だいたいリファレンスに書いてある


テスト


テスト機能は範囲外

  • Selenium WebDriver はテスト機能はもたない
  • テストは各言語のテスティングフレームワークと組み合わせる
  • テストでは以下のものが最低限必要
    • ブラウザー (Firefox, Chrome, etc...)
    • WebDriver (geckodriver, chromedriver, etc...)
    • 言語バインディング
    • テスティングフレームワーク (JUnit, xUnit, Cucumber, etc...)

テストコード (xUnit.NET)

C#
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)

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 ありだとこんな感じ

C#
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 モード

一番単純なモード

Untitled(1) (1).png

  • Java が不要

Standalone モード

Untitled(2) (1).png

  • 他のマシンに接続できる

C#
// ブラウザーを指定する
var capabilities = new DesireCapabilities();
capablities.SetCapability("browserName", "firefox");

// FirefoxDriver の代わりに RemoteWebDriver を使う
var drivier = new RemoteWebDriver("http://standalone.example.com:4444/wd/hub", capabilities);

Selenium Grid モード

Untitled(3) (1).png


お題目


  • まずは遊んでみよう!
  • ウェブアプリをテストしよう!
  • Selenium Grid を使ってみよう!
  • Selenium Grid を構築してみよう!
  • PageObject パターンを使ってみよう!
  • Appium を使ってみよう!

セットアップ

  • ブラウザーをインストール
    • Firefox, Chrome がいいかも
  • 対応するブラウザーの WebDriver をインストール

テストサイト


まずは遊んでみよう!


ブラウザーの自動操作をするだけ!


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 を構築してみよう!


  • Docker 版を使う手も
  • 高橋さんが LT するよ!

PageObject パターンを使ってみよう!


テストパターンが増えてくるといろいろと厄介

C#
// 標準
driver.FindElement(By.ID("input-title")).SendKeys("たいとる");
driver.FindElement(By.ID("input-desc")).SendKeys("本文");
driver.FindElement(By.ID("input-submit")).Click();
C#
// タイトルなし
driver.FindElement(By.ID("input-title")).SendKeys("");
driver.FindElement(By.ID("input-desc")).SendKeys("本文");
driver.FindElement(By.ID("input-submit")).Click();
C#
// 本文なし
driver.FindElement(By.ID("input-title")).SendKeys("たいとる");
driver.FindElement(By.ID("input-desc")).SendKeys("");
driver.FindElement(By.ID("input-submit")).Click();
C#
// 長いタイトル
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 が変更されても追従しやすいように

C#
// 標準
page.Submit(new {Title = "たいとる", Desc = "本文");
C#
// タイトルなし
page.Submit(new {Title = "", Desc = "本文");
C#
// 本文なし
page.Submit(new {Title = "たいとる", Desc = "");
C#
// 長いタイトル
page.Submit(new {Title = LongText(256), Desc = "本文");


Appium を使ってみよう!


こういうのがテストできる

  • Android/iOS のブラウザー
  • Android/iOS のネイティブアプリ

こっそり、Selenium Grid に追加してあります


好きなのを選んで遊んでください!


もちろん、他のことやってもいいよ!

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up