Seleniumによる自動テストを無人でやらせるサーバーを作りますぞ!
「Seleniumインストール」で Seleniumによる Webブラウザを介してのテストを自動化をやっていますが、Seleniumの真髄は Gridという分散テスト自動実行環境にあると思っています。
Seleniumのサイトに Gridの説明がありますので、詳しくはこちらを参照して下さい。
Grid
Gridのことを簡単に書きますと、以下の要素になるかと思います。
- サーバーでテストを実行する
- サーバーは複数立てられる
- Seleniumのテストを仲介する Java製のサーバープログラムを使う
図にするとこんな感じ。
Gridを沢山作ることによって、テストを同時並行で行うことができ、その取りまとめを Hubが担う構成です。
実際に本気の分散テスト環境を作る場合には、Hubや Gridの機能それぞれに Javaのサーバープログラムを立てる必要があるのですが、ここでは Standaloneという形式の、リモートサーバー 1台でテスト実行まで行う形態の環境を作ります。
1.環境
以下のセットでいきます。
●Selenium Grid側(サーバー)
- Ubuntu Server 24.04
- Open JDK 21.0.3
- Selenium Server (Grid) 4.22.0
- snap版 Firefox 127.0.2-1
Ubuntu Serverのインストールは「Ubuntu 24.04 Server インストール」に、
Open JDKのインストールは「Java SE Development Kit (JDK) 21 インストール」にそれぞれ書いています。
これらが済んでいる事を前提として進めていきます。
テストに使う WEBブラウザは Fireroxだけとします。
Chromeも動きますけど、2つも用意するのが面倒なので…。
snap版の Firefoxは何かと問題が出るんで面倒な人は apt版を得ましょう。
私はやっと問題解決ができたので、ここでは snap版を入れることにしました。
subro@UbuntuServer2404-1:~$ sudo snap install firefox
firefox 127.0.2-1 from Mozilla✓ installed
●クライアント側
- Lubuntu 24.04
- Python 3.12.3
- Selenium 4.22.0 (の Python用モジュール)
これは「Seleniumインストール」の環境そのままです。
クライアント側は正直何でも良いというか、Ubuntu系のデスクトップOSじゃなくても良いし、使う言語も Pythonじゃなくても良いので、皆さんの好みで。
2.Selenium Gridサーバー構築
必須ではないんですが、Selenium Gridのサーバープログラムを実行するための専用ユーザーを作ってそれで動かすことにしました。
subro@UbuntuServer2404-1:~$ sudo adduser selenium
info: ユーザ `selenium' を追加しています...
info: Selecting UID/GID from range 1000 to 59999 ...
info: 新しいグループ `selenium' (1001) を追加しています...
info: Adding new user `selenium' (1001) with group `selenium (1001)' ...
info: ホームディレクトリ `/home/selenium' を作成しています...
info: `/etc/skel' からファイルをコピーしています...
新しい パスワード: OSの[selenium]ユーザーの新規パスワード
新しい パスワードを再入力してください: パスワードをもう一回
passwd: パスワードは正しく更新されました
selenium のユーザ情報を変更中
新しい値を入力してください。標準設定値を使うならリターンを押してください
フルネーム []:Enterキー
部屋番号 []:Enterキー
職場電話番号 []:Enterキー
自宅電話番号 []:Enterキー
その他 []:Enterキー
以上で正しいですか? [Y/n] Y
[selenium]ユーザーができました。
一旦ログアウトして、[selenium]ユーザーでログインし直してから以降を行います。
Selenium Gridのプログラムをダウンロードします。
Downloads
下の方に Selenium Gridのものがあり、ここにある「Latest stable version」のリンクをクリックするとダウンロードが始まります。
でも面倒くさいので、curlコマンドを使ってサーバーで直接落とします。
(URLに示されるパスで、ディレクトリ名が「selenium-4.21.0」、ファイル名が「selenium-server-4.21.0.jar」とそれぞれバージョン番号が入っていますが、過去の例から言うと、ディレクトリ名の 3つ目の番号は「0」に固定されていて、ファイル名の 3つ目の番号はちゃんとバージョンアップに伴い変わるようです。
今時点は丁度両方とも 0になってるだけです。)
selenium@UbuntuServer2404-1:~$ curl -s -k -OL https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.21.0/selenium-server-4.21.0.jar
selenium@UbuntuServer2404-1:~$ ls -l selenium-server-4.21.0.jar
-rw-rw-r-- 1 selenium selenium 37857944 6月 27 06:57 selenium-server-4.21.0.jar
ダウンロードできました。
Selenium Gridのプログラムを実行します。
selenium@UbuntuServer2404-1:~$ java -jar selenium-server-4.21.0.jar standalone
07:09:47.252 INFO [LoggingOptions.configureLogEncoding] - Using the system default encoding
07:09:47.258 INFO [OpenTelemetryTracer.createTracer] - Using OpenTelemetry for tracing
07:09:47.917 INFO [NodeOptions.getSessionFactories] - Detected 4 available processors
07:09:47.918 INFO [NodeOptions.discoverDrivers] - Looking for existing drivers on the PATH.
07:09:47.919 INFO [NodeOptions.discoverDrivers] - Add '--selenium-manager true' to the startup command to setup drivers automatically.
07:09:48.013 WARN [SeleniumManager.lambda$runCommand$1] - Unable to discover proper chromedriver version in offline mode
07:09:48.033 WARN [SeleniumManager.lambda$runCommand$1] - Unable to discover proper msedgedriver version in offline mode
07:09:48.481 INFO [NodeOptions.report] - Adding Firefox for {"browserName": "firefox","platformName": "linux"} 4 times
07:09:48.514 INFO [Node.] - Binding additional locator mechanisms: relative
07:09:48.537 INFO [GridModel.setAvailability] - Switching Node 484b37b6-edfa-4b06-a0a6-e4e566a9426f (uri: http://192.168.1.103:4444) from DOWN to UP
07:09:48.539 INFO [LocalDistributor.add] - Added node 484b37b6-edfa-4b06-a0a6-e4e566a9426f at http://192.168.1.103:4444. Health check every 120s
07:09:48.662 INFO [Standalone.execute] - Started Selenium Standalone 4.21.0 (revision 79ed462ef4): http://192.168.1.103:4444
立ち上がりました。
[4444/tcp] で待ち受けていて、ピンク色の部分がテストプログラムに必要ですので覚えておきます。
これで Selenium Grid側の準備は終了です。
3.テストプログラム実行
こちらはクライアントの Lubuntuでの作業です。
Seleniumの Pythonのモジュールの実行環境を作るのは、「Seleniumインストール」に書いている通りですので、これができているのが前提となります。
では、テストプログラムを作ります。
私はLubuntu 24.04で実行しますが、他でも変わらないでしょう。
テストスクリプトはこのように。
[test_grid_py]
import unittest
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
class OkaneKakenai(unittest.TestCase):
def setUp(self):
firefox_options = webdriver.FirefoxOptions()
firefox_options.add_argument("--headless")
firefox_options.binary_location = "/snap/firefox/current/usr/lib/firefox/firefox"
self.driver = webdriver.Remote(command_executor='http://UbuntuServer2404-1:4444',options=firefox_options)
print (firefox_options)
def test_search_in_python_org(self):
driver = self.driver
driver.get("https://subro.mokuren.ne.jp/")
self.assertIn("お金をかけずにサーバーの勉強をしよう", driver.title, '---理由--- タイトルが間違っています。')
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main()
Selenium Gridを実行した時に [4444/tcp]で待ち受けていたのを反映したのがピンクの箇所です。
( [UbuntuServer2404-1] は [/etc/hosts]ファイルで名前解決されるようになっています。)
このサイトのトップページにアクセスして、タイトルに「お金をかけずにサーバーの勉強をしよう」と入っているかのテストをするようになっています。
では、テストしてみます。
subro@Lubuntu2404:~/work/python/selenium$ /home/subro/.local/share/pipx/venvs/selenium/bin/python test_grid.py
<selenium.webdriver.firefox.options.Options object at 0x732de8b54380>
.
----------------------------------------------------------------------
Ran 1 test in 7.514s
OK
実行したテストが 1つで、結果は [OK] って出てます。
スクリプトを変更してわざとエラーになるようにして、もう一回テスト。
import unittest
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
class OkaneKakenai(unittest.TestCase):
def setUp(self):
firefox_options = webdriver.FirefoxOptions()
firefox_options.add_argument("--headless")
firefox_options.binary_location = "/snap/firefox/current/usr/lib/firefox/firefox"
self.driver = webdriver.Remote(command_executor='http://UbuntuServer2404-1:4444',options=firefox_options)
print (firefox_options)
def test_search_in_python_org(self):
driver = self.driver
driver.get("https://subro.mokuren.ne.jp/")
self.assertIn("お金をかけてサーバーの勉強をしよう", driver.title, '---理由--- タイトルが間違っています。')
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main()
実行します。
subro@Lubuntu2404:~/work/python/selenium$ /home/subro/.local/share/pipx/venvs/selenium/bin/python test_grid.py
<selenium.webdriver.firefox.options.Options object at 0x79c2d1a1c560>
F
======================================================================
FAIL: test_search_in_python_org (__main__.OkaneKakenai.test_search_in_python_org)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/subro/work/python/selenium/test_grid.py", line 18, in test_search_in_python_org
self.assertIn("お金をかけてサーバーの勉強をしよう", driver.title, '---理由--- タイトルが間違っています。')
AssertionError: 'お金をかけてサーバーの勉強をしよう' not found in 'お金をかけずにサーバーの勉強をしよう' : ---理由--- タイトルが間違っています。
----------------------------------------------------------------------
Ran 1 test in 3.860s
FAILED (failures=1)
うむ、お金をかけてお勉強するのは誤りのようです。
リモートサーバー(GUIなし)にある Firefoxをヘッドレスで動かして、Webアクセスのテストを自動化することができました。
ここではFireFoxでやっていますが Chromeでも同じ様にすればできるはずです。
Windowsサーバーで Selenium Gridのサーバーを立てれば Edgeでもできるでしょう。
==========
Gridを複数のサーバーに展開していくにはもう少しお勉強が必要ですが、使う Javaのファイルは同じものですし、そんなに難しくはなさそうです。
私にとってはテストスクリプトをいっぱい書くほうが大変で…。
Jenkinsから Seleniumの環境に連携することができるようですし、クライアントPCからテストを実行するのではなく、CI/CDツールから実行させるようにすれば、仕事の時間外にテストをやらせておけますよね。
「どこにサーバーエンジニアとの接点が?」と思われる方もいらっしゃいましょうが、複数のプログラマが共有できるテスト環境、Jenkinsなどとの連携、そういったキーワードが出てくるといきおいサーバーエンジニアが環境を作ることになります。
サーバーエンジニアのしごとでは本番環境の構築と維持に目が行きがちですが、開発環境やテスト環境の構築・維持も多いですよ。
こうして Selenium Gridを使えるようになりましたが、実はこれまでのバージョンには問題があって中々上手く行かなかった経緯があり、それを「Seleniumの WebDriver周りの話」に書いています。
WebDriver(geckodriver)と Firefoxの関係について図示しているので、よろしければそちらもご覧ください。
以上で Selenium Gridのお話はおしまいです。