1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

selenium自動処理用の基底クラスを作成してみました

Posted at

selenium自動処理用の基底クラス

概要

seleniumを使って自動テストを作成する際以下のようなコードをたくさん書くことになるかと思います。
self.driver.find_element_by_xpath(webElement).click()

操作内容の数だけ記述すると結構な量になったり修正が必要になったら全部の箇所を修正することになりかなり面倒だったので基底クラスを作ってそれを継承させたクラスで制御しました。

今回はChromeとFireFoxで確認は取っています。
言語としてはPythonで要素の指定にはXpathを使っています。

画面が動的に変わる場合はXpathの方が指定が楽だからXpathを使っています。

必要なもの

  • python 3.7.2
  • selenium
  • 対応ブラウザのwebdriver

エクセルで作った入力データを登録していくツールを作成した都合上

  • numpy
  • pandas
  • openpyxl
  • xlrd

も使用していましたが今回の範囲では不要です。

公開場所

githubで公開してみました。
調べながら作ったのでまだまだ甘い部分もあるかと・・・

実装説明

インスタンス作成処理

処理の説明

  • driverはクラスのインスタンス作成の際引数で渡すことで呼び出し元で制御します。
  • waitは画面の要素が待つ時間を設定します。time.sleepで待機させるコードをよく見かけますが、こちらの方法なら指定したものが表示したりクリックできるようになり次第即座に操作を行えるようになります。
  • logは独自に作ったlogようのクラスです。loggingを使って作っています。
  • screenShotBaseNameはスクリーンショットの接頭辞に使っています。
    driver=None
    wait=None
    log=None
    # スクリーンショットを格納するディレクトリ
    screenShotBaseName=None

    # 初期化処理
    def __init__(self,driver,log,screenShotBaseName='screenShot'):
        self.driver=driver
        # 画面描画の待ち時間
        self.wait=WebDriverWait(self.driver,20)
        driver.implicitly_wait(30)
        self.log=log
        self.screenShotBaseName=screenShotBaseName+'/'+datetime.now().strftime("%Y%m%d%H%M%S")+'/'
        os.makedirs(self.screenShotBaseName,exist_ok=True)

画面操作処理 クリック

画面のクリック処理です。
継承先のクラスでこの処理を呼び出すことで要素がクリックできるまで待ってクリックするようになり、失敗した場合はスクリーンショットを取るようにしています。
指定ミスなどで要素がない場合は20秒ほどでエラーになります。

    # 画面要素をクリックする 要素が表示されるまで20秒待つ さらに待ち時間が必要な場合は指定を行う
    def webElementClickWaitDisplay(self,webElement,waitTime=0):
        try:
            time.sleep(waitTime)
            self.wait.until(expected_conditions.element_to_be_clickable((By.XPATH,webElement)))
            self.driver.find_element_by_xpath(webElement).click()
        except RuntimeError as err:
            self.log.error('画面要素押下失敗:'+webElement)
            self.log.error('例外発生 {}'.format(err))
            self.getScreenShot()
            raise
        except:
            self.outputException(webElement)
            raise

画面操作処理 クリック マウス移動

画面によってはクリック後マウスを移動させないとメニューが出ないなどある場合は
以下のようにクリック後マウスを移動させます。

    # 画面要素をクリックしてマウスを移動させる クリックした後のメニューの操作を行いたいときに使用する
    # 待ち時間が必要な場合は指定を行う
    # 画面の要素がクリックできるまでまつ
    def webElementClickAndMoveWaitDisplay(self,webElement,waitTime=0):
        try:
            time.sleep(waitTime)
            self.wait.until(expected_conditions.element_to_be_clickable((By.XPATH,webElement)))
            target = self.driver.find_element_by_xpath(webElement)
            actions = ActionChains(self.driver)
            actions.click(target).move_by_offset(10,10).perform()
        except RuntimeError as err:
            self.log.error('画面要素押下失敗:'+webElement)
            self.log.error('例外発生 {0}'.format(err))
            self.getScreenShot()
            raise
        except:
            self.outputException(webElement)
            raise

画面操作処理 テキスト送信

テキスト送信処理
クリックできるまで待ってから送信しています。

    # テキストを送る 要素が表示されるまで20秒待つ さらに待ち時間が必要な場合は指定を行う
    def sendTextWaitDisplay(self,webElement,sendTexts,waitTime=0):
        try:
            time.sleep(waitTime)
            self.wait.until(expected_conditions.element_to_be_clickable((By.XPATH,webElement)))
            self.driver.find_element_by_xpath(webElement).clear()
            self.driver.find_element_by_xpath(webElement).send_keys(sendTexts)
        except RuntimeError as err:
            self.log.error('テキスト送信失敗:'+webElement)
            self.log.error('例外発生 {}'.format(err))
            self.getScreenShot()
            raise
        except:
            self.outputException(webElement)
            raise

画面操作処理 スクロール

画面でスクロールしたい時用
FireFoxの場合画面の範囲外の要素を操作しようとするとエラーになることがあるので
こちらの処理でスクロールして実施しました。
またスクリーンショットを取る時に微妙に動かしたいときのためスクロール処理も共通化しました。
正の値で上に負の値で下に移動します。

FireFoxのみ確認Chromeではまだ未検証

    # 指定した位置までスクロールを行う
    def moveScroll(self,webElement):
        # スクロール確認の処理 指定した位置までスクロールを行う
        try:
            self.wait.until(expected_conditions.visibility_of_element_located((By.XPATH,webElement)))
            inputLabel=self.driver.find_element_by_xpath(webElement)
            self.driver.execute_script("arguments[0].scrollIntoView();", inputLabel)

        except RuntimeError as err:
            self.log.error('画面スクロール失敗:'+webElement)
            self.log.error('例外発生 {0}'.format(err))
            self.getScreenShot()
            raise
        except:
            self.outputException(webElement)
            raise

    # 画面をスクロールさせる
    def adjustScroll(self,offset):
        try:
            self.driver.execute_script("window.scrollTo(0, window.pageYOffset +"+str(offset)+")" )

        except RuntimeError as err:
            self.log.error('画面スクロール失敗:'+str(offset))
            self.log.error('例外発生 {0}'.format(err))
            self.getScreenShot()
            raise
        except:
            self.log.error(traceback.format_exc())
            self.getScreenShot()
            raise

実際例

実装例

以下のようにSeleniumOperationBaseを継承してsuper()で呼び出すことができます。

class Login(SeleniumOperationBase):

    def __init__(self,driver,log,screenShotBaseName='screenShotName'):
        super().__init__(driver,log,screenShotBaseName)

    def loginMethod(self,userId,password):

        self.driver.get(TARGET_URL)
        useridForm=self.driver.find_element_by_xpath(LOGIN_USER_ID)
        useridForm.clear()
        super().sendTextWaitDisplay(LOGIN_USER_ID,userId)
        passwordForm=self.driver.find_element_by_xpath(LOGIN_PASSWORD)
        passwordForm.clear()
        super().sendTextWaitDisplay(LOGIN_PASSWORD,userId)
        super().webElementClickWaitDisplay(LGOIN_LOGINBUTTON)
1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?