Pythonを使ってQRコード読み込みの自動テストを構築してみた

初めに

はじめまして。決済認証システム開発事業部の中口と申します。 現在、担当プロジェクトが佳境に差し掛かってきておりまして、テストを行う機会が増えてきましした。

テストはとても重要なのですが、作業が単調だったり、項目が多かったり、人為的な作業が多いため抜け漏れが発生したりと、悩みはつきものです。

ですので、Python + Seleniumを使ってテストの自動化を構築してみました。上記の悩みが全て解決しますね。

今回は、その中でも私自身が苦労したQRコードの取得と読み込みの機能をご紹介させて頂きます。

Seleniumとは何か

まず初めにSeleniumとは何か。 Seleniumとは、ブラウザを自動的に操作するライブラリです。 主にWEBアプリケーションのテストやWEBスクレイピングに利用されます。 詳しくは、 Seleniumと調べていただければたくさん出てきますので、ここでは実際にこんなことが出来るよという一例をご紹介いたします。

例)テコテックの採用サイトより、社員の平均年齢を取得する

1)Google Topページへ行き「テコテック」を検索します。

f:id:teco_nakaguchi:20200423224236p:plain
"Google and the Google logo are registered trademarks of Google LLC, used with permission."

 driver.get("https://www.google.com/")    #Google Topページを開きます

driver.find_element_by_name('q').send_keys("テコテック")   #検索BOXにテコテックと入力します

driver.find_element_by_name('btnK').send_keys(Keys.ENTER)  #Google検索を押下します

find_element_by_name('q') は検索BOX(name属性が'q')を見つけています。 find_element_by_name('btnK')も同様にname属性が'btnK'を見つけてクリックしています。


2) 検索結果から1件目のテコテックのホームページに入ります。

f:id:teco_nakaguchi:20200423224218p:plain
"Google and the Google logo are registered trademarks of Google LLC, used with permission."

driver.find_element_by_tag_name('h3').click()    #1件目のh3タグをクリックします



3) ホームページに入り採用サイトのリンクを押します。 f:id:teco_nakaguchi:20200423224200p:plain

driver.find_element_by_id('gNav07').click()   #id属性がgNav07をクリックします


4) ヘッダーの「社員データ」を押下します。 f:id:teco_nakaguchi:20200423224144p:plain

 #新しいタブが開くのでそのタブへ移動します
allHandles = driver.window_handles
driver.switch_to_window(allHandles[1])

#10番目のdrawer-menu-item classをクリックします
driver.find_elements_by_class_name('drawer-menu-item')[9].click()

switch_to_windowを使って、新しく開いたウィンドウに移動します。 find_elements_by_class_nameelementsの部分を複数形にすることでclass名が重複しているものをリストで取得できます。 そこから数字を指定して目的の箇所を見つけることが出来ます。


5) 目的のテキストを取得します。 f:id:teco_nakaguchi:20200423224128p:plain

#目的のテキストを取得します
average_age_text = driver.find_element_by_class_name('age_text').find_element_by_tag_name('span').text

print("平均年齢は" + average_age_text + "です")


テキストを表示します。
f:id:teco_nakaguchi:20200423225233p:plain

無事34.5歳が取得できました。

このようにSeleniumを使えばWEB画面を直接操作して、想定の動作をしているか、目的の値を取得できているか、など一連の作業を一括で実施することが可能です。

私の場合、
・目的のチケット買う⇒購入確認画面で正しく購入できているか、金額が正しいか確認
・新規会員登録をする⇒個人情報入力⇒正しく個人情報が登録されているかの確認
等のような処理を何十も一括でテストしています。

上記の例のソース全体はこちらになります。

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


#処理の内容を記載
def get_average_age():

    driver.get("https://www.google.com/")    #Google Topページを開きます

    driver.find_element_by_name('btnK').send_keys(Keys.ENTER)  #Google検索を押下します

    driver.find_element_by_tag_name('h3').click()  #1件目のh3タグをクリックします

    driver.find_element_by_id('gNav07').click()   #id属性がgNav07をクリックします

    #新しいタブが開くのでそのタブへ移動します
    allHandles = driver.window_handles
    driver.switch_to_window(allHandles[1])

    #10番目のdrawer-menu-item classをクリックします
    driver.find_elements_by_class_name('drawer-menu-item')[9].click()


    #目的のテキストを取得します
    average_age_text = driver.find_element_by_class_name('age_text').find_element_by_tag_name('span').text
    print("平均年齢は" + average_age_text + "です")

if __name__ == "__main__":
    driver = webdriver.Chrome()

    #処理実行
    get_average_age()

from selenium import webdriverにてSeleniumからwebdriverをインポートする必要があります。 Seleniumは事前にPCにインストールの必要がありますので、下記参照ください。

mylife8.net

QRコードの自動テスト

前置きが長くなりましたが、ここからは私が実際に構築していく中で苦労したQR情報の取得および読み込みについてご紹介いたします。 決済認証システム開発事業部ですので、決済のシステムを作っています。 そうすると、QRコード決済は今の流行ですよね。 なので当然避けては通れない機能になります。 ただQRコードって携帯電話のカメラで読み込むものですよね。。 ん、PC上でQR読み込みの自動でテストするってどうするんだってなるわけです。

WEBで調べても、断片的にはあるもののまとまった情報が無かったのでこちらでご紹介させていただきます。

QR情報の取得

QRコードの読み込みに関して、大きく分けて2段階のstepが存在いたします。
1)QRコードの情報を取得する
2)取得した情報をもとにRequest処理をする

まずは1)QRコードの情報取得について。 皆さんが日ごろ目にするQRコードですが、こちら目的に応じたデータが格納された画像になります。 ですのでまずは、そのQRコードのデータを取得するところから始まります。

そのために
・ZBar
・pyzbar
上記2種類のライブラリをインストールします。

qiita.com

インストールが完了しましたら下記のソースにてQRコードのデータを取得することができます。

from selenium import webdriver
from pyzbar.pyzbar import decode
from PIL import Image

#実行内容
def qr_code():

    driver.get("【任意のURL】")    #任意のページを開く

    #①目的のQRをスクショします
    png = driver.find_element_by_tag_name("【任意のタグ】").screenshot_as_png

    #②スクショ画像を保存
    with open('./img.png', 'wb') as f:
        f.write(png)

    #③保存した画像を指定
    image = './img.png'

    #④指定した画像を読む
    data = decode(Image.open(image))
    code = data[0][0].decode('utf-8', 'ignore')
    print(code)

if __name__ == "__main__":
    driver = webdriver.Chrome()

    #処理実行
    qr_code()

コンソールエリアにてQRコードに格納されているデータが表示されたかと思います。

取得したQR情報のリクエスト処理

上記にて無事QRコードの情報は取得できたかと思います。 では早速読み込んで処理をしようと思いましたが、PC上ですとカメラで読み込むというリクエスト処理の発火点がないのです、、
通常はカメラで読み込むことが前提ですので、当然QR情報送信ボタンなどもありません。

ですので下記のコードにてリクエスト処理を実装いたします。 こちらは先ほどのQRコードの情報取得を行った続きに記載します。

import requests

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#スマホ等であればカメラがあるページへ移動
    driver.get("【任意のURL】")

    #トークンを取得します
    token = driver.find_element_by_name('_token').get_attribute("value")

    # post送信先のURLを設定
    url = "【 post送信先のURL】"

    #トークンとQRコードより取得したデータを合わせる
    #codeは事前に取得しているQRコードのデータ
    reservation_code = {'_token': str(token) , 'reservation_code': str(code)}

    #セッションの受け渡し
    session = requests.session()
    for cookie in driver.get_cookies():
        session.cookies.set(cookie["name"], cookie["value"])

    #cookieを取得
    response = session.get("【 responseのURL】")
    response_cookie = response.cookies

    #POSTリクエスト
    result = session.post(url, reservation_code, response_cookie)

    #画面遷移
    driver.get(result.url)

これで、無事に(疑似的に)QRコードを読み取って処理をすることが出来ました。 決済システムの自動化テストって感じですよね。

今後

こちらのテストなんですが、ステージング環境や本番環境にマージする工程とは独立しています。 環境を更新する際にテストをかませられればなお良くなるなとは思っているのですが、なかなか連動が上手くいっておらず。。。
今後は、こちらの自動テストを組み込めるよう精進してまいります。

tecotec.co.jp