Knowlbo 開発者ブログ

株式会社Knowlboの開発者ブログです。

Selenium WebDriver で Web アプリのテストを自動化中

開発部の本橋です。

ブラウザ自動化ツールの Selenium WebDriver を使って Web アプリケーションのテスト自動化を試しています。

今回は弊社 Web サイトを例として、Python3 を使って Google Chrome を操作してみます。

の前に Selenium WebDriver とは

Selenium

一言で言えば Web ブラウザ自動化ツールです。以前提供されていた Selenium RC のアーキテクチャはすでに非推奨となり、現在は Selenium WebDriver の開発が活発に行われています。

Selenium WebDriver は W3C で WebDriver として標準化されています。

W3C WebDriver

Selenium WebDriver の Python バインディング

Selenium WebDriver は様々なプログラミング言語で利用できますが、今回は Python3 を使いました。ドキュメントはこちらを参考に。

https://seleniumhq.github.io/selenium/docs/api/py/api.html

環境構築

必要なものをインストールします。Mac で Homebrew を使うことを想定しています。

  • Python3 をインストール
    • Homebrew なら brew install python3
  • Google Chrome をインストール
    • Homebrew なら brew cask install google-chrome
  • ChromeDriver をインストール
    • Homebrew なら brew install chromedriver
  • selenium の Python バインディングをインストール
    • pip なら sudo pip3 install selenium

Selenium WebDriver 基本

アサーションはひとまず置いといて、Selenium WebDriver を使ってみます。

www.google.co.jp で「株式会社Knowlbo」を検索し、トップページから会社案内ページへ遷移してみます。

# selenium_test.py

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()

# Google で Knowlbo を検索
driver.get('https://www.google.co.jp')
elem = driver.find_element(By.NAME, 'q')
elem.send_keys('株式会社Knowlbo')
elem.send_keys(Keys.RETURN)

# www.knowlbo.co.jp へのリンクが表示されるまで待ち、遷移
WebDriverWait(driver, 10) \
    .until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, '株式会社ナルボ'))) \
    .click()

# www.knowlbo.co.jp のページが表示されるまで待ち、会社案内ページに遷移
WebDriverWait(driver, 10) \
    .until(EC.title_contains('株式会社ナルボ'))
driver.find_element(By.LINK_TEXT, '会社案内') \
    .click()
$ python3 selenium_test.py

unittest モジュールと組み合わせる

次は unittest モジュールを使ってアサーションしてみます。(www.google.co.jp からの遷移は省略します。)

# selenium_test3.py

import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class WedDriverTest(unittest.TestCase):
    def _to_knowlbo(self):
        # トップページへ遷移
        driver.get('https://www.knowlbo.co.jp')
        WebDriverWait(driver, 10) \
            .until(EC.title_contains('株式会社ナルボ'))

    def setUp(self):
        self._to_knowlbo()

    def test_company_page_link(self):
        # トップページに会社案内のリンクが表示されることのアサーション
        elem = driver.find_element(By.LINK_TEXT, '会社案内')
        self.assertIsNotNone(elem, 'トップページに会社案内のリンクが表示されること')

    def test_company_page_content(self):
        # 会社案内ページへ遷移
        driver.find_element(By.LINK_TEXT, '会社案内') \
            .click()
        WebDriverWait(driver, 10) \
            .until(EC.title_contains('会社案内'))

        # 会社案内ページの内容のアサーション
        elem = driver.find_element(By.CSS_SELECTOR, '.page-title')
        self.assertEqual(elem.text, '会社案内', '会社案内ページが表示されること')

    def tearDown(self):
        pass

if __name__ == '__main__':
    driver = webdriver.Chrome()
    unittest.main()
$ python3 selenium_test2.py
..
----------------------------------------------------------------------
Ran 2 tests in 11.026s

OK

gif

Chrome を自動操作している gif 動画を取ってみました。イメージ伝わりますかね。

f:id:knowlbodev:20170421162117g:plain

WebDriver は動作に Web ブラウザが必要なのでCIと組み合わせるのは厳しい気がしますが、この調子でどんどん自動化していけたらいいなと思います。

自作の ASP.NET アプリを乗せた Windows コンテナをビルドする

開発部の本橋です。

Windows コンテナで ASP.NET (4.6) Web アプリを実行しようとしてみたら意外と簡単にできたのでメモっておきます。

Web アプリを用意

簡単な Web アプリを用意します。今回は以下のような仕様としました。

  • ASP.NET MVC 5 (.NET Framework 4.6.2) で実装。
  • テキストエリアに任意の文字列を入力可能。
  • “POST” ボタンをクリックするとサーバー上にテキストファイルを出力。
  • 出力したテキストファイルはブラウザからアクセス可能。

コード

コントローラーとビューのコードは以下のようにしました。(ASP.NET MVC プロジェクトの作り方は省略します。)

// コントローラー
using System.IO;
using System.Web.Mvc;

namespace MyWebApp.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home/Index
        // POST: Home/Index
        public ActionResult Index()
        {
            if (this.Request.HttpMethod.ToLower() == "post") {
                var text = this.Request.Form["text"];
                var path = Path.Combine(this.Request.PhysicalApplicationPath, "out.txt");

                using (var sw = new StreamWriter(path, false)) {
                    sw.Write(text);
                }
                var appPath = this.Request.ApplicationPath.EndsWith("/")
                    ? this.Request.ApplicationPath
                    : this.Request.ApplicationPath + "/";
                this.ViewBag.file = appPath + "out.txt";
            }
            return this.View();
        }
    }
}
// ビュー
@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <div>
        <form action="~/" method="post">
            <textarea name="text"></textarea>
            <button type="submit">POST</button>
        </form>
        @if (this.ViewBag.file != null) {
            <a href="@this.ViewBag.file" target="_blank">@this.ViewBag.file</a>
        }
    </div>
</body>
</html>

コンテナイメージを作る

Web アプリを発行

上記のコードをどこかのフォルダに発行します。今回は “C:\_work\MyWebApp\app” フォルダに発行したとして進みます。

Dockerfile

dockerhub のマイクロソフト公式アカウントに microsoft/aspnet というコンテナイメージがあるのでこれを使うと簡単です。

以下の内容を “C:\_work\MyWebApp\Dockerfile” として保存します。

FROM microsoft/aspnet:4.6.2

RUN mkdir c:\inetpub\wwwroot\MyWebApp
COPY app\* c:/inetpub/wwwroot/MyWebApp
RUN powershell -Command "New-WebApplication -Site 'Default Web Site' -Name 'MyWebApp' -PhysicalPath 'c:\inetpub\wwwroot\MyWebApp' -ApplicationPool 'DefaultAppPool'" \
    && icacls c:\inetpub\wwwroot\MyWebApp /grant IIS_IUSRS:F

やってることは簡単で、

  1. 発行した Web アプリをコンテナにコピー
  2. Web アプリケーションを作成
  3. フォルダにアクセス権限を与える

です。COPY 命令のコピー先フォルダのパス区切り文字は \ でなく / にする必要があるので気をつけます。

また、今回はコンテナ上にファイルを出力するため Web アプリケーションの物理フォルダに書き込めるようアクセス権限を設定します。

注:通常、コンテナ上に永続的な目的のファイルを出力するべきではありません。今回は実装の簡略化のためにコンテナ上に出力していますが、本来はホストのファイルシステムをマウントしたり、データボリュームコンテナを利用したりします。

コンテナイメージをビルド

docker build コマンドでイメージをビルドします。ベースイメージである microsoft/aspnet の容量が10GBほどあるため、キャッシュがない場合は結構時間がかかります。

cd c:\_work\MyWebApp
docker build -t mywebwpp .

実行

docker run コマンドでビルドしたコンテナを実行します。

docker run -d mywebapp

ブラウザでアクセスしてみましょう。

f:id:knowlbodev:20170217174201p:plain

“POST” ボタンをクリック↓

f:id:knowlbodev:20170217174202p:plain

“/MyWebApp/out.txt” のリンクをクリック↓

f:id:knowlbodev:20170217174203p:plain

ちゃんと動いている事が確認できます。これで自作の Web アプリケーションを Windows コンテナで実行できました!

Docker for Windows 1.13.0 が出たので Linux コンテナと Windows コンテナの切り替え機能を試してみる

開発部の本橋です。

Docker 1.13.0 の安定版がリリースされました。それに伴って Docker for Windows 1.13.0 の安定版もリリースされています。

Docker for windows

従来 Linux コンテナと Windows コンテナの共存は「出来なくはないがとても面倒」な状況でしたが、Docker for Windows 1.13.0 では簡単に共存、そして切り替えが出来るようになりました。ということで早速使ってみました。

コンテナの切り替え

タスクトレイの Docker アイコン右クリックすると「Switch to Windows Containers…」 または 「Switch to Linux Containers…」 というメニューが出て来るのでクリックします。

f:id:knowlbodev:20170125174820p:plain

数秒時間がかかりますが、「Docker is switching…」のアイコンが消えれば完了です。

f:id:knowlbodev:20170125174829p:plain

どっちのコンテナを使っているか?

docker version の出力の Server の OS/Arch でわかります。

Linux コンテナの場合は「linux/amd64」となっています。

> docker version
Client:
 Version:      1.13.0
 API version:  1.25
 Go version:   go1.7.3
 Git commit:   49bf474
 Built:        Wed Jan 18 16:20:26 2017
 OS/Arch:      windows/amd64

Server:
 Version:      1.13.0
 API version:  1.25 (minimum version 1.12)
 Go version:   go1.7.3
 Git commit:   49bf474
 Built:        Wed Jan 18 16:20:26 2017
 OS/Arch:      linux/amd64
 Experimental: true

Windows コンテナの場合は「windows/amd64」となっています。

>docker version
Client:
 Version:      1.13.0
 API version:  1.25
 Go version:   go1.7.3
 Git commit:   49bf474
 Built:        Wed Jan 18 16:20:26 2017
 OS/Arch:      windows/amd64

Server:
 Version:      1.13.0
 API version:  1.25 (minimum version 1.24)
 Go version:   go1.7.3
 Git commit:   49bf474
 Built:        Wed Jan 18 16:20:26 2017
 OS/Arch:      windows/amd64
 Experimental: true

Linux コンテナ

ごく普通に使えます。

> docker pull debian
> docker run -it debian /bin/bash
(ここからコンテナ)
# uname -a
Linux 9c4b258fd680 4.9.4-moby #1 SMP Wed Jan 18 17:04:43 UTC 2017 x86_64 GNU/Linux

Windows コンテナ

こちらもごく普通に使えますね。

> docker pull microsoft/windowsservercore
> docker run -it microsoft/windowsservercore cmd
(ここからコンテナ)
> systeminfo
Host Name:                 E631F61C1E29
OS Name:                   Microsoft Windows Server 2016 Datacenter
OS Version:                10.0.14393 N/A Build 14393
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Server
(略)

images とか ps

docker imagesdocker ps で見えるイメージやコンテナの一覧は現在有効な方しか表示されないようです。

> docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
debian              latest              e5599115b6a6        8 days ago          123 MB

(ここで切り替え)

> docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
microsoft/aspnet              latest              e761eca2f8df        6 days ago          10.1 GB
microsoft/windowsservercore   latest              4d83c32ad497        2 weeks ago         9.56 GB

コンテナが動いている時に切り替えると?

ステータスが「Up」のコンテナがあるときに切り替えても「Exited」になったりはしないようです。ただし docker ps してもコンテナは見えません。

> docker run -d -p 8081:80 nginx

(ブラウザで http://localhost:8081 にアクセスすると nginx がちゃんと返してくれる)

(ここで切り替え)

(切り替え後も nginx はちゃんと返してくれる)
(ただし ps しても nginx は見えない)
> docker ps
CONTAINER ID        IMAGE                         COMMAND             CREATED             STATUS              PORTS               NAMES
e631f61c1e29        microsoft/windowsservercore   "cmd"               11 minutes ago      Up 10 minutes                           festive_boyd

Linux コンテナも Windows コンテナも両方気軽に使えるようになりました!