Adways Advent Calendar 2017 1日目の記事です。
http://blog.engineer.adways.net/entry/advent_calendar_2017
こんにちは!まっちゃんです。
さっそくですが、アドベントカレンダーのトップバッターを務めさせていただきます!
さて、本日はある業務を自動化した話を書きます。
現在、私たちのチームでは個人ミッションを掲げています。 自分が掲げた個人ミッションの1つに工数入力チェック業務自動化があります。
毎日自分がどの業務をどれくらい行ったのか、登録するシステムが社内にあります。 基本的に終業時にそのシステムにアクセスをして登録をするのですが、中には忘れる人もいます。 現状は都度チームのマネージャーが確認して、未入力などがあればSlack等でやりとりを行い対応をしています。
これは自動化できるのではないかと、チームのマネージャーであるK先輩にヒアリングしたところ 「入力されているかしか確認をしていない」とのことだったので、 未入力者をSlackへ通知するスクリプトを開発しました。
スクリプトはRubyとSelenium-WebDriverを使いました。
まずはSelenium-WebDriverの導入
今回はGoogle Chromeでどのように動いているのかも見たかったので、下記よりChromeDriverをインストールします。
https://sites.google.com/a/chromium.org/chromedriver/downloads
対象のドライバーをインストールしましたら、 ~/.rbenv/shims/
へ配置します。
コマンドなら下記の感じでダウンロードから、配置までいけると思います。
$ cd ~/tmp $ wget https://chromedriver.storage.googleapis.com/2.33/chromedriver_linux64.zip $ unzip chromedriver_linux64.zip $ cp ~/tmp/chromedriver ~/.rbenv/shims/
Rubyの方では、selenium-webdriver
というgemが提供されているので、bundler経由で入れます。
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "selenium-webdriver"
Gemfileに記述しましたら、インストールします。
$ bundler install --path vendor/bundle
これで準備は完了です。
ログインをどうしようか
工数入力チェックする際に、ログインをしないといけません。
例えば、このようなログインフォームがあったとします。
<form action="/login" method="post"> <label>id : <input type="text" name="id"></label><br> <label>password : <input type="password" name="password"></label><br> <input type="submit" value="login"> </form>
このようなRubyスクリプトを書けばログインすることができます。
#!/usr/bin/env ruby require 'selenium-webdriver' def main driver = Selenium::WebDriver.for :chrome driver.navigate.to 'http://localhost/demo/' id_element = driver.find_element(:name, 'id') password_element = driver.find_element(:name, 'password') id_element.send_keys ENV['USER_ID'] password_element.send_keys ENV['USER_PASSWORD'] password_element.submit driver.quit end main
実行してみます。
$ USER_ID=machaaaan USER_PASSWORD=************ bundler exec ruby script1.rb
実際に簡易のログインフォームを作ってみてやってみました。
ざっくり解説します。
driver = Selenium::WebDriver.for :chrome driver.navigate.to 'http://localhost/login/'
webdriver経由でGoogle Chromeを立ち上げ、 対象のページ(今回はログインフォームのあるページ)へアクセスします。
id_element = driver.find_element(:name, 'id') password_element = driver.find_element(:name, 'password')
フォームの要素を取得します。
id_element.send_keys ENV['USER_ID'] password_element.send_keys ENV['USER_PASSWORD'] password_element.submit
send_keysメソッドで、取得したフォームの要素に対して入力を行います。
今回は環境変数で外に定義したものを入力します。
submitメソッドで入力確定(キーボード入力で言うエンターですね!)をします。
driver.quit
webdriver経由で立ち上げたGoogle Chromeを閉じます。
ちなみに余談ですが、サーバー側で認証を挟んでいる際は下記のように対応します。
driver.navigate.to "http://#{ENV['AUTH_USER']}:#{ENV['AUTH_PASSWORD']}@localhost/top/"
どの要素を取得しようか
工数を登録するシステムの詳しい仕様を知らなかったので、調べてみました。
どうやら、未入力など異常があった場合は違うclass名になるようです。
... <th class="column">27</th> <th class="column">28</th> <th class="alert-column">29</th> <th class="alert-column">30</th> ...
これは class="alert-column"
を取得すればいけそうです。
if driver.find_elements(:class, 'alert-column').size != 0 alert_elements = driver.find_elements(:class, 'alert-column') else alert_elements = [] end
find_elementsメソッドで指定した要素をすべて取得します。
alert_elementsには、class="alert-column"
の要素で取得されたものが格納されています。
str = '' alert_elements.each do |item| str += "#{item.text}日 " end
textメソッドで、取得した要素の中にある文字を取得できます。
こうすれば 29日 30日
という形になります。
slackに通知をしよう
今回はwebhookで通知します。 slackのwebhook設定を行い、webhook用のURLを取得します。
Ruby側は slack-incoming-webhooks
というgemがあるので、Gemfileに追記します。
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "selenium-webdriver" gem "slack-incoming-webhooks" ### [Add]
bundler経由でインストールします。
$ bundler install
Ruby側のスクリプトは下記のようにします。
#!/usr/bin/env ruby require 'slack/incoming/webhooks' def main slack = Slack::Incoming::Webhooks.new ENV['WEBHOOK_URL'], channel: ENV['SLACK_CHANNEL'], username: 'てすと' slack.link_names = 1 slack.icon_emoji = ':cake:' slack.post "スクリプトから通知できとーと?できとーよ! @here" end main
環境変数でwebhookURLとチャンネル名を指定します。
実行してみます。
$ WEBHOOK_URL=webhookのURL SLACK_CHANNEL=#test_ch bundler exec ruby script2.rb
下記のようにSlackへ通知されます。
ここまでできたらスクリプト同士を組み合わせていい感じにします。
完成。そして。
個人ミッションの進捗を確認するミーティングが昨日あったので、 チームのマネージャーのK先輩とT先輩に見せました。
好評だったのでさっそくチームのSlackチャンネルに導入することになりました。
下記は実際に本日実行してみた画像です。
cronなどで定期的に回すようにすれば、自動化完了です!
まとめ
初めてSeleniumを触ってみたり、Rubyスクリプトを書いてみましたが、純粋に楽しかったです!
現在はe2eテストなどが盛り上がってきている感じもしているので、
この経験を活かして、既存システムのe2eテスト化などに切り込んでいけたらなと思います。