TravisCIでDockerに入ったWebアプリのSeleniumテスト

 WebアプリをDockerでビルドして、そこでできたイメージをデプロイしてコンテナを走らせるってケースは増えてきているはず。そのイメージを使ってTravisCI上でSeleniumを使ってテストしてみる。


 Dockerイメージは既にDocker Hubにアップしてあるものとする。今回使うのは、Webアプリで、リクエストを送ると世界へのあいさつを返すだけのごく初歩的なものだ。テストはSeleniumを使ってリクエストを送り、レスポンスのHTMLのタイトルをチェックするものとする。

 テストに使うSeleniumを用意する。Seleniumはホスト環境に用意するのもいいが、仮想ディスプレイを使ったりすると、自分の環境でTravisCIでやるコマンドをちょっと試したかったりする場合に用意が手間になる。SeleniumもDockerで公式のものが用意されているので、今回はDockerで用意されたものを使う。

 Seleniumを動かすテストコードは、今回はPythonを使う。
 DockerコンテナとしてWebアプリとSeleniumが動いており、ホストにSeleniumを動かすPythonがあるというのが今回の環境。コンテナが二つあるので、ここらはdocker-composeを使うことにする。

 まずWebアプリとSeleniumのある環境の準備のためにdocker-compose。docker-compose.ymlを用意する。
docker-compose.yml

version: '2'

services:
tornadoapp:
image: matoba/tornadoapp
ports:
- "80:80"
selenium:
image: selenium/standalone-chrome
ports:
- "4444:4444"
links:
- tornadoapp

 WebアプリはTornadoを使って作ったのでtornadoappという名前にしてある。ポートバインドで、ホストのポート80でこのWebアプリがlistenされることになっている。
 あとSeleniumは、Pythonドライバで接続するためにポート4444でlistenしているのと、Webアプリに名前でアクセスができるようにlinksで設定してある。
 環境はこれでOK。

 ホストで動く、Seleniumを動かすPythonを用意する。"python setup.py test"のコマンドで動かすので、setup.pyと実際のテストコードを用意する。./TestWithSelenium以下にsetup.pyと、tests/s_test.pyが必要。
setup.py

from setuptools import setup
import sys

sys.path.append('./tests')

setup(
name='browsertest',
version='1.0',
description='test a project on browser',
test_suite = 's_test.suite',
install_requires=[
'selenium',
],
)


s_test.py

import unittest

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

#HOST = "http://172.17.0.1"
HOST = "http://tornadoapp"

class BrowserTests(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Remote(
command_executor = 'http://127.0.0.1:4444/wd/hub',
desired_capabilities = DesiredCapabilities.CHROME
)
self.driver.implicitly_wait(10)

def test_top(self):
"""top page"""
self.driver.get(HOST + "/")
self.assertIn("foo", self.driver.title)

def suite():
"""run tests"""
suite = unittest.TestSuite()
suite.addTests([unittest.makeSuite(BrowserTests)])
return suite


if __name__ == '__main__':
unittest.main()

 SeleniumからWebアプリへのアクセスはdocker-composeで設定した名前で行っている。その他の手段としては、ポートがホストにバインドされていれば、IPでアクセスできる。Dockerネットワークのデフォルトは172.17.0.*なのでこれを使っていいはず。

 テストが用意できたら、あとはこれをTravisCIで動かすための設定ファイルを用意する。
.travis.yml

sudo: required

language: python

python:
- 3.6

services:
- docker

env:
- DOCKER_COMPOSE_VERSION=1.8.0

before_install:
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
- docker-compose build
- docker-compose up -d
- pip install selenium

script:
- cd ./TestWithSelenium
- python setup.py test

matrix:
fast_finish: true

 やっていること↓
前準備
・Dockerを使えるように
・docker-composeコマンドを使えるように
・WebアプリコンテナとSeleniumコンテナを用意
・PythonのSeleniumドライバを用意
テスト
・Pythonコードを走らせる

 これでTravisCIでコンテナに入ったWebアプリを、Seleniumでテストする準備ができた。あとはアップするだけ。設定などを間違えていなければこれでテストは通る。




今回のTravisCI
https://travis-ci.org/hMatoba/PlayDockerTest
comment: 0

Dockerコンテナに入った.NET Core WebアプリのSeleniumでのテスト

 Visual Studio 2017から、.NET CoreのWebアプリにDockerサポートがつけられるようになった。



 これを選択してWebアプリを作成すれば、DockerコンテナでそのWebアプリを動かすための設定ファイルも自動生成される。これでWebアプリは容易にコンテナ化できる。今回はこのコンテナに入れたアプリをSeleniumでテストできるようにする。
 今回の一連のファイル準備から変更は、Githubで追えるようにしてある。
https://github.com/hMatoba/DNCinDC


 まずなにはともあれ、VisualStudio2017でWebアプリを作る。.NET Core製で、もちろんDockerサポートを有効にして作成する。ファイル一式が自動生成されたら、とりあえずデバッグを実行してみる。




 デバッグを実行するたびに、ホストにバインドされるポートの番号が変わる。これがデバッグでは面倒なことになるので、ポート番号を固定してしまう。docker-compose.ymlを編集し、ポート固定の設定を加える。



docker-compose.yml

version: '2'

services:
webapp:
image: webapp
build:
context: ./WebApp
dockerfile: Dockerfile
ports:
- "8888:80"

https://github.com/hMatoba/DNCinDC/commit/24847963b7ee5e3422d0b9f08b2cea71cd389719


 続いてSeleniumを用意する。と言ってもaptだのyumだのを使ってごにょごにょしない。Dockerコンテナで手っ取り早く用意する。
 再びdocker-compose.ymlを開き、Seleniumコンテナの用意を追記する。
version: '2'


services:
webapp:
image: webapp
build:
context: ./WebApp
dockerfile: Dockerfile
ports:
- "8888:80"
selenium:
image: selenium/standalone-chrome
ports:
- "8889:4444"
links:
- webapp

 seleniumのツリーでportsの設定によって、ホスト環境の8889ポートでseleniumがlistenするようになっている。linksは、SeleniumコンテナからWebアプリにホスト名で接続できるように書いている。こう書くことで、Seleniumコンテナから、作成したWebアプリコンテナへは、"http://webapp"でアクセスできる。
 ここでデバッグをVisuslStudioでおこない、コンテナが用意されたのち"http://127.0.0.1:8889"へブラウザでアクセスすれば、Seleniumがコンテナによって用意されたのが確認できる。

 あとはSeleniumを使ったテストを書く。C#でSeleniumを動かすのはめんどうだという経験があるので、今回はPython3.6で用意する。モジュールはunittestを使うので別途インストールはいらないが、seleniumドライバをpipあたりで用意しておく。
 ソリューション内に、Pythonプロジェクトを追加する。デフォで作成されたPythonスクリプトをリネームし、setup.pyに変更する。そしてsetup.pyの中身は下記。
from setuptools import setup

import sys

sys.path.append('./tests')

setup(
name='browsertest',
version='1.0',
description='test a project on browser',
test_suite = 's_test.suite',
install_requires=[
'selenium',
],
)

 続いてテストスクリプトを用意する。テストプロジェクトとして作られたPythonプロジェクトにtestsというディレクトリを作成し、そこにs_test.pyを作成する。中身は下記。
import unittest


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

HOST = "http://webapp"

class BrowserTests(unittest.TestCase):
"""tests for main five functions."""

def setUp(self):
self.driver = webdriver.Remote(
command_executor = 'http://127.0.0.1:8889/wd/hub',
desired_capabilities = DesiredCapabilities.CHROME
)
self.driver.implicitly_wait(10)

def test_top(self):
"""top page"""
self.driver.get(HOST + "/")
self.assertIn("Home Page", self.driver.title)



def suite():
"""run tests"""
suite = unittest.TestSuite()
suite.addTests([unittest.makeSuite(BrowserTests)])
return suite


if __name__ == '__main__':
unittest.main()

 これでPythonによってSeleniumをドライブさせるテストは用意できた。ここでVisualStudioのテストエクスプローラを見てみる。そこにPythonで書いたテストが表示されるはずである。ソリューションをリビルドしてもそこになにも出てこなければ、いったんVisualStudioを落として立ち上げ直す。
 テストエクスプローラにテストが表示されたら、デバッグを実行し、コンテナを動かし直す。コンテナが用意されたのを確認出来たら、テストエクスプローラにある、実行したいテストを選んで実行する。”すべて実行”を選ぶと、ソリューションのリビルドが走ってコンテナが思い通りに動作しなくなる。だからテストは部分的に実行。



https://github.com/hMatoba/DNCinDC/commit/30a1406591bc16e4469107d9c21d7e187a8ed159


 .NET CoreのWebアプリをE2Eでテストできるようにした。これでCIに進める。
comment: 0

最近行ってきたセミナーが面白かった

 あるクラウドサービスのリリースまでの話をセミナーで聞いてきた。そこで聞いた「ウォーターフォールがベストな選択肢だった」という話が、最近DevOpsを追っているぼくには膝を打つような感覚があったのでメモがてら。

 なぜアジャイルが生まれたのか。これはおそらくビジネスの状況の変化(また場合によってはクライアントの不明瞭さ)により、開発中にも仕様を変更していく必要があったためだ。一方で、サービスリリースを考えたとき、仕様がしっかり固まっているものを描けるならそれに沿ってやっていくのが実はベストなんじゃないかと。
 「設計をしっかりやったから手戻りがなかった」ということを、ウォーターフォールのメリットとしてセミナーで語っていた。設計書をしっかり練って書いて、あとはそれに沿ってクラスを書いていく。そんな工程で手戻りなく開発を進めていけたということだ。こういうことを可能にするような設計って、一般で考えればビジネスも開発も熟知していなければできない。んー、開発と同時にこういう設計できるようになりたい。
 ちなみにリリースが済んでからはアジャイルに移行していったとのこと。とても自然な形だと思う。
comment: 0

DockerコンテナからWindowsホストにホスト名アクセス

 Azureのファイルストレージエミュレータを使った開発を行う場合、コンテナに入れたWebアプリからストレージエミュレータを参照するには、ホストマシンへアクセスできないといかん。ホストのIPを調べて、コンテナにホスト名でアクセスできるように渡してやる。
docker run --rm -it --add-host MyComputer:10.0.75.1  debian /bin/bash

あとはコンテナ内で好き放題。
ping MyComputer


 IPで解決してもいいんだけどコンテナ内にハードコーディングで埋め込んでしまうのもアレだったので(IP固定だと趣味の開発でコワーキングスペースとか行ったときに面倒になる)。
 ちなみにWindowsでやることを考えているので、PowerShellでスクリプトを書いてホストのIPを自動取得してもいい。環境変数dnat_ipに、DockerNATアダプタでつないでいるネットワークのIPを入れてみる。
set-item env:dnat_ip -value ( `

Get-NetIpaddress `
| Where InterfaceAlias -eq "vEthernet (DockerNAT)" `
| Select -ExpandProperty IPAddress `
)


 ↑を使えば、さっきのコンテナのコマンドは下記のようになる。
docker run --rm -it --add-host MyComputer:$Env:dnat_ip  debian /bin/bash
comment: 0

価値の流れに基づいた組織

金融機関のDevOpsの取り組み

 ロンドンで行われた金融業界のITカンファレンス。DevOpsという言葉に誘われて読んでみた。さらには金融機関での取り組みということで、これほど興味をそそるものはない。だって、日本にいると銀行って、DevOpsとは遠い開発手法とってるイメージがあるから。

 なにをした?なにを導入した?どういう目的で?といった内容か。やはりDevOpsなので、自動化して、リリースを早くといったところか。ところで目を奪われる言葉が記事中に出てきた。”価値の流れに基づいた組織”。
 以前に”ITというものの捉え方の更新を怠っていた”という記事を書いたばかり。要はITっていうのもいろいろ変わっていくよね、もうスマフォあるんだからほぼ24時間365日に近い状態でコンシューマに手を伸ばすことができるよねという状況。じゃあ今ってコンシューマにいいUXを与える技術の価値が飛躍的に高まってるんじゃないかと。そもそも技術に限ったことでもなく、価値って流動的なものなんじゃないかと。
 個人的な某所で、どう儲けるかって話を聞いていると、「開発したあそこのシステムが当たってハネてくれればサポートでうちは安泰になる」というのを繰り返し聞いている。これって価値が流動的だって考えをしていないから言えるのよね。価値は流動的、ましてやITなんてヒョイヒョイと標準が変わっていくので、IT界隈での価値の流動性は激しい。だからITやってる組織としては、市場ではなにに価値があるか、自分たちの手が届くところではどういうものが価値があるとされているか、自分たちがどういう価値を創出できるのかというのを逐一アップデートしながらやっていくべきなんじゃないかって思った。おそらく”価値の流れに基づいた組織”ってそういうことやってるんだろう。


 しかしイギリスは”英国政府、新ポータルGov.ukをクラウド、アジャイル、Rubyで開発。ソースはGithubで公開”とかやってて実験的なものを交えながらだいぶ面白いやり方を進めてるなーと。
comment: 0