Appiumを使って、リグレッションテストを自動化する

みなさんこんにちは!、20卒入社の山口です。自分は研修後Optimal Bizの開発チームに配属になりました!

今回は自分が担当しているタスク、Optimal Biz(Android)のリグレッションテストの自動化の過程を紹介していきたいと思います。

【開発環境】

  • ホストOS(テストコードを動かすPC)…Windows10
  • テストを実行する端末のOS…Android10
  • Ruby (Ver.2.6)
  • Appium (v1.17.1-1)

背景

リグレッションテストとはプログラムの一部を修正した時に、その影響でほかに不具合が出ていないかをチェックするためにおこなうテストです。 Optimal BizのAndroid版では、従来版と現行版の2種類が展開されています。 従来版ではこのテストが自動化されていましたが、現行版の方では仕様が大きく変わってしまいこの自動化が後回しになっていました。 今回はこの自動化を進めていくことを目的にしています。

Appiumとは

AppiumはスマートフォンやPCなどの端末に対してタップやテキスト入力などを実行することができる、フレームワークです。Webブラウザの自動テストを実行する際に使用される「Selenium WebDriver」から派生したものでAndroidやiOS、Windowsなども扱うことができます。また使用できる言語も多く、公式対応しているのは、Java、C#、Ruby、Python、JavaScript (Node.js)があります。

Appiumのインストール

今回はAppium GUIを使用します。流れは以下のとおりです。

  1. JDK(Java SE Development Kit 8)をインストール
    • インストール後、環境変数を設定する。
      • JAVA_HOME ... Javaのinstall path(ex. C:\Program Files\Java\jre1.8.0_171 )
      • Path ... 実行フォルダのパス(ex. %JAVA_HOME%\bin )
  2. Android Studioをインストール
    • インストール後、環境変数を設定する。
      • ANDROID_HOME ... androidのSDKのinstall path「File」>「Other Settings」>「Default Setting Structure…」の"SDK location"
      • Path ... adb等の実行フォルダのパス(ex. %ANDROID_HOME%\platform-tools)
  3. appium GUI版のインストール
    • appium-desktop-setup-x.x.x.exe をダウンロードし、インストールを行う

これらのインストールが終わったら、Androidがデバッグモードで動くように、開発者モードにして、USBデバッグをオンにしておきます。

Rubyのインストール

今回はRubyでテストコードを組みます。ruby + devkitのインストールを行います。 (Windowsインストーラーのリンク https://rubyinstaller.org/) またインストールが終わったら、ライブラリをインストールしていきます。以下のコマンドを入力します。またgemを使ってインストールを行います。使用したGemfileは以下のとおりです。

  • Gemfile
source 'https://www.rubygems.org'

gem 'rspec'
gem 'appium_lib'
gem 'selenium-webdriver'
gem 'ffi'
  • コマンド
gem install bundler
bundle install

テストコードの作成

driverについて

appium_libの主な機能は Appium::Driver のインスタンスメソッドで提供されています。このdriverは以下のコマンドで呼び出します。

def desired_caps
    {
        caps: {
            "deviceName" => "Android Device", # デバイスの名前
            "platformName" => "Android", # プラットフォーム
            "newCommandTimeout" => 30, # タイムアウトまでの秒数
            "unicodeKeyboard" => true, # Unicode入力を有効にする
            "resetKeyboard" => true, # unicodeKeyboard機能を備えたUnicodeテストを実行した後、キーボードを元の状態にリセットします。
        },
        appium_lib: {
            wait: 30
        }
    }
end

driver = Appium::Driver.new(desired_caps).start_driver

desired_caps#caps 内にて様々な設定のパラメーターがあり、ここで定義することによって設定を行えます。appiumの利用状況によってこの設定値は変わると思いますので、詳しくはこのリンクから確認をお願いします。

driverを定義することができたら、このdriverを使用し、端末を操作していきます。

操作の流れとして、driverから画面内の要素(ボタンやテキスト入力バーなど)を指定し、その要素に対して、クリックや文字入力を行います。要素の指定や操作について最初はAppiumのGUIツールを使用する方法がおすすめです。

Appium-GUIツールを使用し、コードを生成する方法

  1. Appium-GUIを起動します
  2. 虫眼鏡のボタンを押下します

    f:id:optim-tech:20200901141749p:plain

  3. JSON Representationの値を編集し、セッションを開始します

    f:id:optim-tech:20200901141753p:plain

    f:id:optim-tech:20200901141756p:plain

  4. 動作の記録を行います。目のアイコンを押下するとこれから行う操作を指定したプログラミング言語に変換してくれます。

    f:id:optim-tech:20200901141807p:plain

  5. GUIツールからAndroidを操作します。

    1. 操作したいボタンなどをクリックする。

    2. クリックすると「Selected Element」の欄に「tap」や「Send Keys」などがでてきます。このボタンを押下するとボタンをクリックしたり、テキストボックスに入力したりできます。

      f:id:optim-tech:20200901141759p:plain

    3. 操作後画面が更新されます。

      f:id:optim-tech:20200901141803p:plain

    4. 目のアイコンを押下していた場合、コードが生成されます。

      f:id:optim-tech:20200901141810p:plain

el2 = driver.find_elements(:accessibility_id, "Chrome")
el2.click

このコードを使用することによって、行った操作を再現することができます。(ただし注意点有り)

コード作成

driverの定義の仕方とその操作方法を理解したところで実際にコードを書いていきます。

require 'rubygems'
require 'appium_lib'

def desired_caps
    {
        caps: {
            "deviceName" => "Android Device", # デバイスの名前
            "platformName" => "Android", # プラットフォーム
            "newCommandTimeout" => 30, # タイムアウトまでの秒数
            "unicodeKeyboard" => true, # Unicode入力を有効にする
            "resetKeyboard" => true, # unicodeKeyboard機能を備えたUnicodeテストを実行した後、キーボードを元の状態にリセットします。
        },
        appium_lib: {
            wait: 30
        }
    }
end

driver = Appium::Driver.new(desired_caps).start_driver

el2 = driver.find_element(:accessibility_id, "Chrome")
el2.click

driver.quit # driverを閉じる

注意するべきポイントは、以下のポイントです。

el2 = driver.find_element(:accessibility_id, "Chrome")

GUIツールの方ではfind_elementsとなっていますが、find_elementsは戻り値が配列となるため、el2.clickではエラーを起こしてしまいます。(find_elementsを使用する場合、el2[0].clickとすると同じ操作が行えます。)

詳しい仕様につきましては公式のドキュメントなどで確認をしていただけたらと思いますが、GUIツールで作成したコードはそのままだとエラーが起きる場合がありますので、注意していただけたらと思います。

実装していく

今回は実際にテストの一部として実装した、Optimal Bizの認証動作を自動化したコードを紹介します。

# 動作内容:エージェントの認証を行う動作
require 'rubygems'
require 'appium_lib'

class AuthenticationAgent
    def desired_caps
        {
            caps: {
                "deviceName" => "Android Device",
                "platformName" => "Android",
                "newCommandTimeout" => 30,
                "unicodeKeyboard" => true,
                "resetKeyboard" => true,
                "allowTestPackages" => true
            },
            appium_lib: {
                wait: 30
            }
        }
    end

    def action(app_info, arg_driver = nil)
        if arg_driver == nil then
            # Android Driver 開始
            driver = Appium::Driver.new(desired_caps,true).start_driver
            driver.manage.timeouts.implicit_wait = 30
            driver_wait = Selenium::WebDriver::Wait.new :timeout => 30
        else
            driver = arg_driver
            driver_wait = Selenium::WebDriver::Wait.new :timeout => 30
        end

        # アクティビティのスタート
        system("adb shell am start -n #{app_info["app_package"]}/#{app_info["app_activity"]}")

        driver_wait.until { driver.find_element(:id => "#{app_info["app_package"]}:id/AuthenticateButton").displayed? }
        # 「起動」ボタンの押下
        driver.find_element(:id, "#{app_info["app_package"]}:id/AuthenticateButton").click

        # 認証
        # 企業コード
        company_code = driver.find_element(:id, "#{app_info["app_package"]}:id/TextCompanyCode")
        company_code.send_keys app_info["login_info"]["company_code"]
        driver.press_keycode(66) #キーボードのENTERのコード

        # 認証コード
        authentication_code = driver.find_element(:id, "#{app_info["app_package"]}:id/TextAuthCode")
        authentication_code.send_keys app_info["login_info"]["auth_code"]
        driver.press_keycode(66) #キーボードのENTERのコード

        # URL
        rpc_url = driver.find_element(:id, "#{app_info["app_package"]}:id/TextRpcUrl")
        rpc_url.clear
        rpc_url.send_keys app_info["login_info"]["url"]
        driver.press_keycode(66) #キーボードのENTERのコード

        # 送信ボタン
        driver.find_element(:id, "#{app_info["app_package"]}:id/nextButton").click
        driver.find_element(:id, "#{app_info["app_package"]}:id/okButton").click

        if arg_driver == nil then
            driver.back
            driver.quit
        end
    end
end

if $0 == __FILE__
    hash = {
        "app_package" => "パッケージ名",
        "app_activity" => "アクティビティ名",
        "login_info" => {
                    "company_code" => "企業名",
                    "auth_code" => "認証コード",
                    "url" => "サーバーURL"
                }
    }
    action = AuthenticationAgent.new
    action.action(hash)
end

これを実行すると以下のように動作します。(サーバーURLの部分は隠してあります)

f:id:optim-tech:20200901141706g:plain

他にもOptimal Bizの認証だけでなく、同期の動作を行ったり、他のアプリを動かしたりなどして総合テストを作っています。 (まだまだ開発途中ではありますが...)

将来的にはビルドサーバーに接続してガンガン回していきたいですね!

まとめ

今回はAppiumの使用方法や簡単なコードの作成の仕方などを紹介しました。一度コードを作成すれば、あとは自動で動作を行ってくれるので業務の効率化に繋がります!

オプティムではタスクの自動化に興味があるエンジニアを募集しています。