ラベル appium の投稿を表示しています。 すべての投稿を表示
ラベル appium の投稿を表示しています。 すべての投稿を表示

2014年8月12日火曜日

AppiumでAndroidのChromeを動かすための二つの方法

AppiumでAndroidのChromeを動かす時に、portlait、landscapeを変更したいという要望があると思います。
それはやり方によっては可能なのですが、その方法をappiumの仕組みと共に考えていきます。
AppiumでAndroidのChromeを動かす際に、二つの方法があります。
  • Chromeをアプリとして動かす方法
  • Chromeをブラウザとして動かす方法
それはどう違うのか。

まずはアプリとして動かす方法から説明します。

appium.txtの中身
./chrome.apkはダウンロードしてきたchromeアプリです。
端末はGalaxy Nexusです。
[caps]
platformName = "android"
platformVersion = "4.3"
deviceName = "Nexus"
app = "./chrome.apk"
#appの変わりにこの二つでも動きます。
appPackage = "com.android.chrome"
appActivity = "com.google.android.apps.chrome.Main"

[appium_lib]
debug = true
wait = 30
export_session = true
appiumサーバーの起動
node .
appium/lib/server/main.jsが読み込まれて、サーバーがListen状態になります。 実行されているのがこれです。
var main = function (args, readyCb, doneCb) {}
別ターミナルで、clientを動かします。
arc
その時のappium server側の動作です。 appium/lib/appium.jsが読みこまれます。
Appium.prototype.start = function (desiredCaps, cb) {
  console.log("start in appium.js");
  console.log(desiredCaps);
  this.desiredCapabilities = new Capabilities(desiredCaps);
  this.updateResetArgsFromCaps();

  this.args.webSocket = this.webSocket; // allow to persist over many sessions
  if (this.sessionId === null || this.sessionOverride) {
    this.configure(this.args, this.desiredCapabilities, function (err) {
      if (err) {
        logger.debug("Got configuration error, not starting session");
        this.cleanupSession();
        cb(err, null);
      } else {
        this.invoke(cb);
      }
    }.bind(this));
  } else {
    return cb(new Error("Requested a new session but one was in progress"));
  }
};
configureで何をやっているか。
Appium.prototype.configure = function (args, desiredCaps, cb) {
  var deviceType;

  try {
    deviceType = this.getDeviceType(args, desiredCaps);
    if (!args.launch) desiredCaps.checkValidity(deviceType, args.enforceStrictCaps);
  } catch (e) {
    logger.error(e.message);
    return cb(e);
  }

  if (!this.deviceIsRegistered(deviceType)) {
    logger.error("Trying to run a session for device '" + deviceType + "' " +
                 "but that device hasn't been configured. Run config");
    return cb(new Error("Device " + deviceType + " not configured yet"));
  }
  this.device = this.getNewDevice(deviceType);
  console.log("configure in appium.js");
  console.log(deviceType);
  this.device.configure(args, desiredCaps, cb);
  // TODO: better collaboration between the Appium and Device objects
  this.device.onResetTimeout = function () { this.resetTimeout(); }.bind(this);
};
deviceTypeには「android」が入っています。 このメソッドでオブジェクトを生成しています。 deviceTypeによって、生成されるオブジェクトが変わります。
Appium.prototype.getNewDevice = function (deviceType) {
  console.log("prototype.getNewDevice");
  console.log(deviceType);
  var DeviceClass = (function () {
    switch (deviceType) {
      case DT_IOS:
        return IOS;
      case DT_SAFARI:
        return Safari;
      case DT_ANDROID:
        return Android;
      case DT_CHROME:
        return Chrome;
      case DT_SELENDROID:
        return Selendroid;
      case DT_FIREFOX_OS:
        return FirefoxOs;
      default:
        throw new Error("Tried to start a device that doesn't exist: " +
                        deviceType);
    }
  })();
  return new DeviceClass();
};
次に呼び出されるのは appium/lib/devices/android/android.js
Android.prototype.start = function (cb, onDie) {}
この中でuiautomator.jsが呼び出されています。
UiAutomator = require('./uiautomator.js')
uiautomatorを通してChromeアプリを動かす流れになります。
この場合は、このメソッドが使えます。
pry(main)>driver.rotation = :portlait
pry(main)>driver.rotation = :landscape
この場合は、このメソッドは使えません!
pry(main)>driver.get("http://google.co.jp")

次にブラウザで動かす方法です。

[caps]
platformName = "android"
platformVersion = "4.3"
deviceName = "Nexus"
browserName = "Chrome"

[appium_lib]
debug = true
wait = 30
export_session = true
この流れは同じ
Appium.prototype.start = function (desiredCaps, cb) {}
};
configureで何をやっているか。
Appium.prototype.configure = function (args, desiredCaps, cb) {
  var deviceType;

  try {
    deviceType = this.getDeviceType(args, desiredCaps);
    if (!args.launch) desiredCaps.checkValidity(deviceType, args.enforceStrictCaps);
  } catch (e) {
    logger.error(e.message);
    return cb(e);
  }

  if (!this.deviceIsRegistered(deviceType)) {
    logger.error("Trying to run a session for device '" + deviceType + "' " +
                 "but that device hasn't been configured. Run config");
    return cb(new Error("Device " + deviceType + " not configured yet"));
  }
  this.device = this.getNewDevice(deviceType);
  console.log("configure in appium.js");
  console.log(deviceType);
  this.device.configure(args, desiredCaps, cb);
  // TODO: better collaboration between the Appium and Device objects
  this.device.onResetTimeout = function () { this.resetTimeout(); }.bind(this);
};
deviceTypeには「chrome」が入っています。 次に呼び出されるのが上記のファイルとは異なります。 appium/lib/devices/android/chrome.js
ChromeAndroid.prototype.start = function (cb, onDie) {}
この中ではchromedriverが呼び出されています。
Chromedriver = require('./chromedriver.js');
この場合は、このメソッドが使えます。
pry(main)>driver.get("http://google.co.jp")
この場合は、このメソッドは使えません!
pry(main)>driver.rotation = :portlait
pry(main)>driver.rotation = :landscape 
 
基本的にはchromedriverで動かす方がわかりやすいし、chromeのバージョンアップにも強いので 後者の方がいいと思います。でも、どうしても縦横を変えたいという時は前者の方法でやればいいのかと思います。

2014年8月4日月曜日

ruby_libを使ってappiumでAndroidを動かす準備

Android ADKのダウンロード
http://developer.android.com/sdk/index.html
ダウンロードしたファイルを/Applicationsに移動
~/.bashrcを編集
vi ~/.bashrc
export ANDROID_HOME="/Applications/adt-bundle-mac-x86_64-20140702/sdk"
export PATH=$PATH:$HOME/.rvm/bin:/Applications/adt-bundle-mac-x86_64-20140702/sdk/tools:/Applications/adt-bundle-mac-x86_64-20140702/sdk/platform-tools
export JAVA_HOME=`/usr/libexec/java_home`
appium-doctorで確認
appium-doctor
以下の用に表示されたらOK
Running Android Checks
✔ ANDROID_HOME is set to "/Applications/adt-bundle-mac-x86_64-20140702/sdk"
✔ JAVA_HOME is set to "/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home."
✔ ADB exists at /Applications/adt-bundle-mac-x86_64-20140702/sdk/platform-tools/adb
✔ Android exists at /Applications/adt-bundle-mac-x86_64-20140702/sdk/tools/android
✔ Emulator exists at /Applications/adt-bundle-mac-x86_64-20140702/sdk/tools/emulator
✔ Android Checks were successful.
Androidのデバッグモードを有効にする。 「設定」=>「端末情報」=>「ビルド番号」を7回タップすると「設定」に開発者向けオプションが表示される 「設定」=>「開発者向け」=>「USBデバッグ」にチェックを入れる
Chrome Driverをインストール(必要ないかも)
 
brew install chromedriver
最後にAndroid端末のChromeバージョンを最新版にアップデート
appium_consoleをインストール
gem install --no-rdoc --no-ri appium_console
appiumがインストールされているか確認
gem list | grep appium
appium_console (1.0.1)
appium_lib (4.1.0)
Appiumサーバーの起動
cd appium
node .
別ターミナルでarcの起動
arc
appium.txtの中身はこんな感じ
[caps]
platformName = "android"
platformVersion = "4.4"
deviceName = "Xperia"
browserName = "Chrome"
  
[appium_lib]
debug = true
wait = 30
export_session = true

2014年4月22日火曜日

appiumでiPhoneのsafariを動かす時のエラー

fruitstrapのコマンドが失敗している

/Users/test/appium_workspace/appium/build/fruitstrap/fruitstrap install --id 99258c06b8ee15fd3e8b378efe5049c5fdbd2855 --bundle /var/folders/5c/qnxxcy2x5sldq1h4v0bg93tcnkyqqn/T/114322-8693-ps0pa3/submodules/SafariLauncher/build/Release-iphoneos/SafariLauncher.app

エラーメッセージはこれ。

Failed to start an Appium session, err was: Error: Unable to install [/var/folders/5c/qnxxcy2x5sldq1h4v0bg93tcnkyqqn/T/114322-8819-17v2gif/submodules/SafariLauncher/build/Release-iphoneos/SafariLauncher.app] to device with id [99258c06b8ee15fd3e8b378efe5049c5fdbd2855]. Error [Error: Command failed: ]

修正方法
appium/lib/devices/ios/ios.jsを修正
fruitstrapを止めて、mobiledeviceを使用することにしました。
ファイルの先頭でmobiledeviceを定義します。
, mobiledevice = '/usr/local/bin/mobiledevice'
IOS.prototype.installApp = function (unzippedAppPath, cb) {
  if (this.args.udid) {
  /** 
    var installQuietFlag = this.args.quiet ? ' -q' : '';
    var installationCommand = fruitstrap + installQuietFlag + ' install --id ' + this.args.udid + ' --bundle ' + unzippedAppPath;
  **/
    var installationCommand = mobiledevice + ' install_app ' + unzippedAppPath;
    deviceCommon.installApp(installationCommand, this.args.udid, unzippedAppPath, cb);
  } else {
    cb(new Error("You can not call installApp for the iOS simulator!"));
  }
};

2014年4月8日火曜日

iOSのテストにおいてのAppiumとCalabashの比較(Comparing the Appium with the Calabash in the iOS test)

スマートフォンテストの自動化でappiumとcalabashのどちらを選ぶかで、迷っている人がいるかもしれない。基本的には、両方ともほとんど同じです。
実機でテストする手順はこんな感じです。

  1. Xcodeでアプリをビルドして実機にインストールする。
    (appiumでもIPAファイルからのテストは上手くいかないため。)
    追記;IPAファイルでのテストは、ビルドした時の署名によります。iPhone Developerによって作成されている場合は動きます。
  2. ruby等で作成されたフレームワークを通して、UIAutomationを操作する。
では、何が違うのか。
  1. In App Purchase等を行う際に出るシステムアラートを、appiumでは補足できるがcalabashでは補足できない。calabashでは、現在、実装中。それについて詳細に書かれているリンクはこちら
  2. フレームワークの便利メソッドを、自分で作成したクラスでも使う仕組みがappiumにはあるけど、calabashにはない。それぐらい自分で作れと言われれば、それまでですが。このメソッドです。Appium.promote_singleton_appium_methods
  3. calabashではテスト時にiphoneとpcで同様のネットワークにいる必要があるが、appiumでは特にそういった必要はない。 
  4. appiumではビルドしたappを外部から操作するが、calabashではappをコピーしたものにテストコードを埋め込んで操作することになる。
上記4点の理由から、私はAppiumをお勧めします。

2014年4月3日木曜日

promote_singleton_appium_methodsが何をやっているか?

common.rbの中に書かれているこのメソッドが気になったので調査してみた。
Appium.promote_singleton_appium_methods UICatalog
pathはここです。
appium_lib/lib/appium_lib/driver.rb
def self.promote_singleton_appium_methods main_module
  raise 'Driver is nil' if $driver.nil?
  main_module.constants.each do |sub_module|
    #noinspection RubyResolve
    $driver.public_methods(false).each do |m|
      const = main_module.const_get(sub_module)
      const.send(:define_singleton_method, m) do |*args, &block|
        begin
          super(*args, &block) # promote.rb
        rescue NoMethodError, ArgumentError
          $driver.send m, *args, &block if $driver.respond_to?(m)
        end
        # override unless there's an existing method with matching arity
      end unless const.respond_to?(m) &&
          const.method(m).arity == $driver.method(m).arity
    end
  end
end
何のためのメソッドか?
自分で作成したmoduleの中でappiumのメソッドを使えるようにするためです。
サンプルでは自分でmoduleを作成しているのですが、
普通に実装しては、その中でappiumのメソッドは使えません。
module UICatalog
  module ButtonUses
    class << self
      def assert_exists
        s_text_exact resolve_id 'ButtonsTitle'
      end
      
      def assert
        wait { self.assert_exists }
      end
    end
  end
end
Appium.promote_singleton_appium_methods UICatalog←これをコメントすれば
NoMethodError: undefined method `wait' for UICatalog::Home:Module
というエラーが出ます。
もう少し、詳細にメソッドを見ていきます。
main_module.constants
これはサンプルでは、下記の内容になります。
UICatalog.constants
戻り値です。
[
    [0] :ButtonUses,
    [1] :ControlUses,
    [2] :Home
]
ここでは$driverに含まれているクラスのメソッドが返ります。
$driver.public_methods(false)
  main_module.const_get(sub_module)
戻り値の一つはこうなります。
UICatalog::ButtonUses
上記の値に対してsendで動的にメソッドを定義します。
define_singleton_methodメソッドは、レシーバのオブジェクトに特異メソッドを定義します。
特異メソッドとはインスタンスから呼び出させるメソッドを定義します。
それで、これがどういう意味なるか?
const.send(:define_singleton_method, m)
下記のような感じでappiumのメソッドの全てをUICatalog::ButtonUsesに追加していきます。
UICatalog::ButtonUses.define_singleton_method(:wait)
UICatalog::ButtonUses.define_singleton_method(:back)
UICatalog::ButtonUses.define_singleton_method(:xpath)

appiumを使ってiphoneの実機でipaファイルを動かす?

appiumサーバーを動かす
node . -U 03923e8c696326912be875c******* --ipa /Users/test/Downloads/showcase.ipa
もう一つのターミナルで起動
vi appium.txt
適切な値を入力
DEVICE="ios"
APP_PATH="net.showcase"
require=["./appium/ios/pages", "./appium/ios/common.rb"]
arc
このエラーが出た時の対処方法
Failed to start an Appium session, err was: Error: Command failed: dyld: Library not loaded: @executable_path/../lib/libimobiledevice.3.dylib Referenced from: /Users/test/appium_workspace/appium/build/libimobiledevice-macosx/ideviceinstaller Reason: image not found
vi ~/.bash_profile
export DYLD_LIBRARY_PATH=/Users/test/appium_workspace/appium/build/libimobiledevice-macosx/:$DYLD_LIBRARY_PATH
export PATH=$PATH:/Users/test/appium_workspace/appium/build/libimobiledevice-macosx/
両方のターミナルでやることを忘れずに!
source ~/.bash_profile
最終的にはiphoneの実機にアプリはインストールされましたが、動作はしませんでした。
そもそもappiumはUIAutomationで動いており、UIAutomationはipaファイルでインストールされたアプリを動かすことが可能なんでしょうか?

追記;IPAファイルが動作する、動作しないはビルドされた時のコード署名によると思います。iPhone Distributionでビルドされている場合は、動作しません。iPhone Developerによって作成されている場合は動くはずです。

2014年4月2日水曜日

iphoneのシステムアラートをappiumで補足する。

How to push system alert at real iphone device by appium
アラートを操作する
  alert_click 'OK'
  alert_click 'キャンセル'
もうちょっと、複雑な操作をしたい時はUIAutomationのコマンドを使う。
  execute_script("target.frontMostApp().keyboard().typeString('password')")

appiumのサンプルコード、UICatalogをiphone実機で動かす

appiumのトレーニングのURLを実行しているとUICatalogを動かしていきます。
リンクはこちら

シュミレーターだと動くのですが、iphoneの実機だと動きません。
I can use it by simulator but I can't use it by real device.

appiumをiphoneの実機で動かすためには、予め、アプリをインストールする必要があるので、XcodeでUICatalogをオープンします。
UICatalogのソースコードはこちらにあります。
git clone https://github.com/appium/appium.git
cd appium/sample-code/apps/UICatalog
Xcodeでオープンします。
open UICatalog.xcodeproj
Bundle Identifierを大文字から小文字に変更します。
タブにあるBuild Settings → PackagingのProduct Nameで変更できます。
変更前
com.example.apple-samplecode.UICatalog
変更後
com.example.apple-samplecode.uicatalog
その後でiphoneにアプリをインストールします。
あとは一緒です。appiumを起動
cd appium
node . -U 03923e8c696326912be875cf64e6532088eb9***
cd training/modules/source/ruby_ios
vi appium.txt
DEVICE="ios"
APP_PATH="com.example.apple-samplecode.uicatalog"
require=["./appium/ios/pages", "./appium/ios/common.rb"]
arc

appiumでiphone実機のテストをする方法(How to use appium by iphone real device)

appiumのinstall
git clone https://github.com/appium/appium.git
rubyとrvmの準備
  curl -sSL https://get.rvm.io
  rvm use 2.1.1
  rvm gemset create appium
  rvm gemset use appium
  gem uninstall -aIx appium_lib ;\
  gem uninstall -aIx appium_console ;\
  gem install --no-rdoc --no-ri appium_console
node.jsのインストール http://nodejs.org/download/
 cd appium
appiumの起動 -U で実機のidentifierを指定
identifierをXcode → Window → Organizerをで確認
node . -U 03923e8c696326912be875cf64e653208****

 
Xcodeを利用してアプリを実機にインストールする
gitのtrainingをclone
  
git clone https://github.com/appium/tutorial.git
cd projects/ruby_ios
appium.txtを開いてBundle IdentifierをAPP_PATHにいれる。
Xcodeでアプリを選択してGeneralタブを選択して確認できます。
  vi appium.txt
DEVICE="ios"
APP_PATH="自分のBundle Identifier"
require=["./appium/ios/pages", "./appium/ios/common.rb"]
  arc

サンプルにあるUICatalogは、そのままでは実機で動きませんでした。
シミュレータのみです。
実機で動かす際には、自分で作成したアプリで動かしました。