Python Lab #3 ― Selenium Web テスト自動化

# Python Lab #3 ― Selenium Web テスト自動化

過去に Web 画面（React、Vue の 2種類の画面）を開発しました。

https://qiita.com/tengbu-haoshou/items/01255518c78b69f6136d

今回、Selenium を使って自動的に Web 画面（React、Vue の 2種類の画面）を操作するという開発をしてみました。
簡単なリグレッションテストとして使えそうです。
ブラウザー（Chrome）をインストールせず、Selenium 内包のブラウザー（Chrome for Testing）を使用しました。便利ですねー。

## テストシナリオ

1. [ログイン] 画面にて、何度かの入力ミスによるログイン失敗ののち、ログインに成功し [ホーム] 画面に飛ぶ。
2. [ホーム] 画面 のタブを使って、[セッティング] 画面に飛んで、[ホーム] 画面に飛ぶ。
3. [ホーム] 画面にて、ログアウトして [ログイン] 画面に飛ぶ。

**[React、React-Bootstrap]**

![PythonLab-auto_test_react.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/6aa4d425-2f0c-ee8e-74dc-9cabf40dbd58.gif)

**[Vue、Vuetify]**

![PythonLab-auto_test_vue.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/c3bb3025-48af-12ee-f797-9a65c94e8957.gif)

## テスト対象画面のソースコードの簡単な説明

* ログイン画面（ほんの一部分）。
    ```tsx:FlaskLogin.tsx
    ・・・
      return (
        <>
          ・・・
          <main style={styles.margin}>
            <h5>Login</h5>
            <Container fluid="true">
              <Row noGutters="true">
                <Col>{message}</Col>
              </Row>
              <Row noGutters="true">
                <Col xs={12} md={4}>
                  <Form.Control type="text" value={userName} id="userName" placeholder="User Name" onChange={(e) => setUserName(e.target.value)} /> ← ★
                </Col>
              </Row>
              <Row noGutters="true">
                <Col xs={12} md={4}>
                  <Form.Control type="password" value={password} id="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} /> ← ★
                </Col>
              </Row>
              <Row noGutters="true">
                <Col md="auto">
                  <Button variant="outline-success" id="login" onClick={login}>Login</Button> ← ★
                </Col>
              </Row>
            </Container>
          </main>
        </>
      );
    ・・・
    ```
    Selenium で画面パーツ（&lt;input&gt;、&lt;button&gt; などに相当するもの）を指定しやすくするために、各画面パーツには “id=” で ID を指定する。
* ブラウザーでテスト対象画面を開いて [F12] キーで DevTools を開いて HTML の内容を参照し、正しく ID が指定されていることを確認する。

![PythonLab-auto_test_html.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/d6e3614b-fc42-1546-f8bb-5b91bad926f8.jpeg)

## Python ソースコードの簡単な説明

* 自動テスト処理。React と Vue で共通のソースコードとなる。
    ```python:auto_tester.py
    #!/usr/bin/env python3
    
    ・・・
    
    # Import Libraries
    import sys
    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.chrome.options import Options
    
    # Constants
    SLEEP_SECONDS = 2
    URL = 'http://localhost:8080'
    CMD_FILL = 1
    CMD_CLEAR = 2
    CMD_CLICK = 3
    CMDS = [
        [CMD_CLICK, 'login'],
        [CMD_FILL, 'userName', 'root'],
        [CMD_CLICK, 'login'],
        [CMD_FILL, 'password', 'asdf1234'],
        [CMD_CLICK, 'login'],
        [CMD_CLEAR, 'password'],
        [CMD_FILL, 'password', 'Asdf1234'],
        [CMD_CLICK, 'login'],
        [CMD_CLICK, 'settings'],
        [CMD_CLICK, 'home'],
        [CMD_CLICK, 'logout'],
    ]
    
    
    # Main
    def main() -> None:
    
        # browser
        options = Options()
        options.add_experimental_option("detach", True)
        driver = webdriver.Chrome(options=options)
    #    driver.maximize_window()
        driver.get(URL)
    
        # processes
        for cmd in CMDS:
            time.sleep(SLEEP_SECONDS)
            if cmd[0] == CMD_FILL:
                html_textbox = driver.find_element(By.ID, str(cmd[1]))
                html_textbox.send_keys(str(cmd[2]))
            elif cmd[0] == CMD_CLEAR:
                html_textbox = driver.find_element(By.ID, str(cmd[1]))
                html_textbox.send_keys(Keys.CONTROL + "a")
                html_textbox.send_keys(Keys.DELETE)
            elif cmd[0] == CMD_CLICK:
                html_button = driver.find_element(By.ID, str(cmd[1]))
                html_button.click()
            else:
                print('Invalid command : %s' % cmd[0], file=sys.stderr)
                raise Exception('Invalid command.')
    
        # end
        time.sleep(SLEEP_SECONDS)
        driver.quit()
        sys.exit(0)
    
    
    # Goto Main
    if __name__ == '__main__':
        main()
    ```
    配列の値（コンマ区切りデータ：動作, 画面パーツ ID ［, テキストボックス文字列］）に従って、画面パーツのテキストボックスに文字列を設定したりボタンを押下したりする。

## 全ソースコードの置き場所

https://github.com/tengbu-haoshou/Python_lab-flask

## 参考

**Selenium 使用方法**

https://qiita.com/MonaSkoog/items/ab66cd78a8bffa9925d0

**Selenium チュートリアル**

https://qiita.com/uneyamauneko/items/c041f95b59026c1273e2

**Selenium 内包ブラウザー（Chrome for Testing）**

https://gammasoft.jp/support/selenium-with-batteries-included/