kuroneko's blog

とりとめもなく気づいたことを書いていく

seleniumによるテストは負荷テストには向かない

pythonseleniumが思ったよりサクサクっと動いてくれるし、 コードとしてシナリオも判定も定義でき、非常にわかりやすい(個人的には)ので、 このまま長期安定化試験で流すシナリオに利用してやればいいんじゃね? と思ったけど、向いている分野でないと思ったのでメモ。

サンプルコード

負荷テストなので

  • 並列実行できる
  • ループして一定期間動作し続ける

ができる必要がある。 サンプルとして下記を用意して試してみた。 (実際は、ページオブジェクト用のソースファイルを別に用意したわけだが)。

  • main.pyにてスレッド化、ループの管理
  • selenium_sample.pyにてunittestを利用して、シナリオを管理

◇main.py

import unittest
import selenium_sample
import threading
import time
from datetime import datetime

# スレッド数
t_number = 2

# スレッドの実行間隔(s)
t_span_time = 2

# ループ回数
roop = 2

# ループ間隔(正確には前回ループ内のスレッドが全て終了してからの間隔)(s)
roop_span_time = 5

# 想定テスト時間(s)
test_time = 40

class MyThread(threading.Thread):
    def run(self):
        # logging.info('Starting...')
        logger.debug('Starting...')
        loader = unittest.TestLoader()
        # テストモジュール単位で追加
        suite = unittest.TestLoader().loadTestsFromModule(selenium_sample)
        # テストスイートを実行
        unittest.TextTestRunner(verbosity=2).run(suite)
        # logging.info('End.')
        logger.debug('End.')
        return


# メイン処理
for r in range(roop):
    threads = []

    for i in range(t_number):
        t = MyThread()
        t.start()
        threads.append(t)
        if i < (t_number - 1):
             time.sleep(t_span_time)

    for thread in threads:
        thread.join(test_time)

    if r < (roop-1):
        time.sleep(roop_span_time)

selenium_sample.py

import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

class PythonOrgSearch(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.PhantomJS()

    def test_sample(self):
        driver = self.driver
        driver.get("http://www.python.org")
        self.assertIn("Python", driver.title)
        elem = driver.find_element_by_name("q")
        elem.send_keys("pycon")
        elem.send_keys(Keys.RETURN)
        driver.save_screenshot("org1.png")
        assert "No results found." not in driver.page_source

    def tearDown(self):
        self.driver.close()

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

実行環境

実行環境は以下のとおり。

メモリ不足

今回用意したコードの場合、phantomjsがスレッド単位で起動する形になる。
スレッド化する際にメソッド(t = threading.Thread(target=hoge,......))だと画面遷移等を絡ませるとうまく動かなかった為、シナリオのクラス自体のインスタンスをrunさせた(知識不足も多々あり。。。)。
その結果、スレッド1つあたり、80MBほどメモリをphantomjs.exeが喰ってしまう。これが結構痛い。 これにより、(物理メモリの空き容量)/80MBがスレッド数の目安(スレッド化できるとは言っていない)になる。

phantomjs.exeのPIDが残る

1ループだけの場合、main.pyが終われば自然とプロセスが全部落ちるのだが、ループさせる場合、空きメモリ容量が不足し出さない限り、リソースモニターを見ていてもメモリには残ったままに見えている。

  • プロセス名が灰色になっている
  • 足りなくなれば一気にメモリが空く(処理が終わったphantomjs.exeが消える)
  • 特にテストも失敗しないし、phantomjsのログにも何も出ない、screenshot等で確認しても無事に進んでいる

といった状況なので、self.driver.close()自体は上手くいっているように見えるのだが、、、、大丈夫か心配になる(何時間か動かしてみたが、特にエラーになることはなかった)。

CPUは割と余裕がある?

適度にsleepを入れるなどフルスロットルで動かさなければ、割と余裕がある(自分が試した別コードは画面表示に2秒ほどsleepを必ず入れているから、という話もある)。

個人的な結論

seleniumはあくまで結合試験観点で、ブラウザを介して試験したい機能試験として利用すべきであり、負荷をかけたい、ということであれば、jmeterあたりが良さそう。

windows + python + selenium + PhantomJSで実行エラー(Network Error)

PhantomJSの使い方はいろんなブログに載っていますが、どうしても「Network Error」というhtmlがwebdriverから帰ってきてしまう状況でした(driver = webdriver.PhantmJS()の部分でエラーになる)。
起動する以前の問題のためか、検索しても引っかからず途方に暮れていたのですが、なんとかなったのでメモとして残します。

結論を言うと、IEのproxy設定を外したら上手くいきました><

自分の場合、社内のproxy環境下において、proxyの除外対象のURLであっても問答無用にエラーになりました。ただ、DOSプロンプトからは実行することができていたことで(phantomjs hello.jsなど)、なぜだ。。。と苦悩しました。家にパソコンを持って帰ってきて、さー原因を探ろうとプロキシを外してインターネット検索しながら動かしてみると、あら不思議、動くじゃありませんか。。。笑うしかなかった。

もし同様の方がいて、解決できる手助けとなれば幸いです。

 

以下は参考情報です。

■環境

■初期設定

  1. pythonをインストール
  2. seleniumのインストール(pip install selenium)
  3. PhantmJSをダウンロードしてパスを通す

ソースコード

下記のように公式サンプルで出てくるやつです。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.PhantomJS()
driver.get("http://www.python.org")
assert "Python" in driver.title
elem = driver.find_element_by_name("q")
elem.clear()
elem.send_keys("pycon")
elem.send_keys(Keys.RETURN)
assert "No results found." not in driver.page_source
driver.close()

■事象

  • Network Errorというhtmlが返ってくる(今サンプルが手元にない)。
  • Chrome("path_to_webdriver.exe")やFirefox()のwebdriverの場合にはちゃんと動く
  • IE("path_to_webdriver.exe")はphantomJS()と同じくエラー(セキュリティ設定のProtected Mode以前の状態)
  • DOSからphantomjs hello.jsなどは動いて、正常に終了する(パス設定、webdriverも問題なさそう)
  • firewallやセキュリティソフトを無効にしても変化なし(エラーのまま)

 

grails twitter bootstrapメモ

grails(version:2.2.4)でtwitter bootsrapを使うときのメモ。

 

pluginsに「runtime ":twitter-bootstrap:3.3.4"」を追加しようとしたら、下記のエラーメッセージが出て困った。

$ grails clean

| Error Failed to resolve dependencies (Set log level to 'warn' in BuildConfig.groovy for more information):
- org.grails.plugins:twitter-bootstrap:3.3.4

 

BuildConfig.groovyに下記を追加することで解消。
[BuildConfig.groovy]
repositories {

    grailsRepo "https://grails.org/plugins"
}

TapCalでのGoogleカレンダーとの同期エラー

なぜか失敗するようになってTapCalのFAQを見たらヒントが出ていた。

ヒント:
Googleカレンダーの一覧は取得しましたか?

Googleとカレンダーの同期を行うには、Googleアカウント設定後に先ずカレンダー設定画面からGoogleカレンダーのリストを 取得する必要があります。

カレンダー設定画面からリストを更新してみたら同期できるようになった。原因は、カレンダーを整理した時に不要なカレンダーを削除していたこと。リストが不一致(存在しないカレンダーを取得しようとして?)により、同期エラーになったっぽい。

解決してよかったよかった。

 

 

 

bluetoothテザリングのLTEモバイルルータ

http://jpn.nec.com/press/201401/20140124_01.html

格安SIMが使えるようならかなり魅力的かも(ビッグローブぷらら@niftyの記載があるのが気になるが)。連続使用時間24時間、bluethoothテザリング、かなりのインパクトがあるような。