Selenium Base の使い方 〜 Python で E2E テストを書こう 〜

## はじめに
Python で E2E テスト書きたいなーと思ってフレームワークを調べてみると、Selenium + Pytest な [SeleniumBase](https://github.com/seleniumbase/SeleniumBase) なるものを見つけたのですが、なんと日本語情報が全くない…
Google 検索した結果こんな感じ。(Seleniumしか出てこない…)
<img width="778" alt="Screen Shot 2018-12-05 at 21.12.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/53708/b25bd0c2-5907-a838-47e9-74d8fa4cb506.png">

ということで、せめてインストールから基本的な使い方ぐらいまでは情報があると便利かなと思い、まとめてみます。

SeleniumBaseではまだ3,4ページ遷移する程度の軽いE2Eテストしか書いていないのですが、使い勝手は悪くないので、PythonでE2Eを書きたい方はぜひ使ってみると良いと思います。

## インストール
http://seleniumbase.com/#-quick-start にインストール方法が書いてあるんですが、あまりQuickではないので、

```
$ pip install seleniumbase
```

でさらにクイックにインストールするのが良いかと思います。
`chromedriver` のインストールも必要なのですが、これは環境によって入れ方が異なります。
macOSであれば

```
$ brew tap caskroom/cask
$ brew cask install chromedriver
```

でいけます。

Pure Python ベースの軽量 Docker Image も作ったので、仮想環境で試したい場合は https://github.com/showwin/docker-seleniumbase を使ってみてください。
Linuxでインストールしたい方は[上のDockerfile](https://github.com/showwin/docker-seleniumbase/blob/master/Dockerfile#L16-L25)を参考にすると良いと思います。

## 使い方

`BaseCase` クラスは `unittest.TestCase` を継承しているので、テストの書き方はunittestと同じです。
こんな感じでテストケースを書くと

```python
import time

from seleniumbase import BaseCase


class GitHubTests(BaseCase):
    def slow_click(self, css_selector):
        time.sleep(1)
        self.click(css_selector)

    def test_github(self):
        self.open("https://github.com/")
        self.update_text("input.header-search-input", "SeleniumBase\n")
        self.slow_click('a[href="/seleniumbase/SeleniumBase"]')
        self.assert_element("div.repository-content")
        self.assert_text("SeleniumBase", "h1")
        self.slow_click('a[title="seleniumbase"]')
        self.slow_click('a[title="fixtures"]')
        self.slow_click('a[title="base_case.py"]')
        self.assert_text("Code", "nav a.selected")

```

こんな感じで、実際にブラウザで動いているのが見えます。

![720](https://user-images.githubusercontent.com/1732016/49517195-e993b600-f8de-11e8-9a2b-9639b613693e.gif)

コンテナ内で動かす場合にはGUIで見れないのが残念ですが、macOS上では実際の画面遷移を見ることができるので、E2Eを書きながらデバッグしやすいと思います。
E2Eはどうしても不安定になりがちなので、確率的にテストが落ちたり通ったりすることがあるかと思いますが、実際の画面遷移が見えないとどのような状態でテストが落ちたのかわからず、デバッグに意外と時間と取られてしまいます。


よく使うようなクリックやフォームへの埋め込みは `self.click()` `self.update_text()` など短いメソッド名でかけるので、コードの見た目もスッキリして良いです。
細かな動きが必要な場合は `self.driver` でSelenium WebdriverのAPIを触ることもできます。

```python
self.driver.find_element_by_css_selector("textarea").send_keys("text")
```

これが

```python
self.update_text("textarea", "text")
```

でかけるのは可読性が高まって嬉しいですね。

## Tips
実際にテストを書いていく上での細かなテクニックです。

### テストの実行順をコントロールする
E2Eの最初にテスト用のアカウントを作成して、最後にそのアカウントを消して終了したいというようなことがあると思います。
pytest ではファイル名のアルファベット順でテストが実行されるので、ファイル名の先頭に実行したい順で数字を振るのが良さそうです。

テストの中身を他でimportすることはないと思うので、テストが増えてきてやっぱりファイル名の数字を変えたい。となっても困ることはないでしょう。

```
$ tree e2e 
e2e
├── 0100_create_account_test.py
├── 0200_dashboard_test.py
├── 0210_dashboard_left_side_test.py
├── 9999_delete_account_test.py
└── __init__.py
```

同一ファイル内では、メソッド名のアルファベット順で実行がされるので、こちらも同様にナンバリングしていくとわかりやすいと思います。

```python
from seleniumbase import BaseCase


class CreateAccountTests(BaseCase):
    def test_0_open_signup(self):
        pass

    def test_1_signup(self):
        pass

    def test_2_1_login_failure(self):
        pass

    def test_2_2_login_success(self):
        pass
```

## おわりに

私もまだ SeleniumBase を深く触ってはいないので、浅い紹介になりましたが、一通り検証するのに必要な情報は提供できたかなと思います。

バグを直した [1行Delete](https://github.com/seleniumbase/SeleniumBase/commit/dc0e683badd056c5cef92ce0984111458f461967) のPullReq出したら、 [Contributorランキング3位](https://github.com/seleniumbase/SeleniumBase/graphs/contributors) になってしまったぐらいだれも貢献してくれていないかわいそうなプロジェクトなので(笑)、ぜひPythonistaの皆さんで育てていきましょう！