80

多くのアクティビティにまたがる多くの画面とワークフローで構成される複雑な Android アプリケーションを構築しています。私たちのワークフローは、銀行の ATM マシンで見られるものに似ています。たとえば、ユーザーの選択に基づいて他のアクティビティに移行できるActivityメイン メニューに移行するログインがあります。Activity

非常に多くのワークフローがあるため、ワークフローをエンドツーエンドでテストできるように、複数のアクティビティにまたがる自動テストを作成する必要があります。たとえば、ATM の例を使用して、有効な PIN を入力し、メイン メニューに移動することを確認し、現金の引き出しを選択し、現金の引き出し画面にいることを確認します。メインメニューに戻るか、「ログアウト」します。

ActivityInstrumentationTestCase2Android (例: ) とPositronに付属するテスト API をいじりましたが、どちらも単一の の範囲を超えてテストすることはできないようですActivity。これらのツールには、いくつかの単体テスト用のユーティリティがいくつかありますが、勝っています。複数のアクティビティにまたがるテスト シナリオのニーズを満たしていません。

xUnit フレームワーク、スクリプト作成、GUI レコーダー/再生などにオープンであり、アドバイスをいただければ幸いです。

4

14 に答える 14

65

自分の賞金に関する質問に答えるのは少し気まずい気がしますが、ここでは...

私はこれについて高低を検索しましたが、どこにも答えが公開されていないとは信じられません。私は非常に近づいてきました。アクティビティにまたがるテストを確実に実行できるようになりましたが、私の実装にはタイミングの問題があり、テストが常に確実にパスするとは限らないようです。これは、複数のアクティビティにわたるテストが成功したことを私が知っている唯一の例です。私の抽出と匿名化によってエラーが発生しなかったことを願っています。これは単純なテストで、ログイン アクティビティにユーザー名とパスワードを入力し、別の「ようこそ」アクティビティで適切なウェルカム メッセージが表示されることを確認します。

package com.mycompany;

import android.app.*;
import android.content.*;
import android.test.*;
import android.test.suitebuilder.annotation.*;
import android.util.*;
import android.view.*;
import android.widget.*;

import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.*;
import static com.mycompany.R.id.*;

public class LoginTests extends InstrumentationTestCase {

   @MediumTest
   public void testAValidUserCanLogIn() {

      Instrumentation instrumentation = getInstrumentation();

      // Register we are interested in the authentication activiry...
      Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(AuthenticateActivity.class.getName(), null, false);

      // Start the authentication activity as the first activity...
      Intent intent = new Intent(Intent.ACTION_MAIN);
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      intent.setClassName(instrumentation.getTargetContext(), AuthenticateActivity.class.getName());
      instrumentation.startActivitySync(intent);

      // Wait for it to start...
      Activity currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
      assertThat(currentActivity, is(notNullValue()));

      // Type into the username field...
      View currentView = currentActivity.findViewById(username_field);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(EditText.class));
      TouchUtils.clickView(this, currentView);
      instrumentation.sendStringSync("MyUsername");

      // Type into the password field...
      currentView = currentActivity.findViewById(password_field);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(EditText.class));
      TouchUtils.clickView(this, currentView);
      instrumentation.sendStringSync("MyPassword");

      // Register we are interested in the welcome activity...
      // this has to be done before we do something that will send us to that
      // activity...
      instrumentation.removeMonitor(monitor);
      monitor = instrumentation.addMonitor(WelcomeActivity.class.getName(), null, false);

      // Click the login button...
      currentView = currentActivity.findViewById(login_button;
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(Button.class));
      TouchUtils.clickView(this, currentView);

      // Wait for the welcome page to start...
      currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
      assertThat(currentActivity, is(notNullValue()));

      // Make sure we are logged in...
      currentView = currentActivity.findViewById(welcome_message);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(TextView.class));
      assertThat(((TextView)currentView).getText().toString(), is("Welcome, MyUsername!"));
   }
}

このコードは明らかに読みにくいです。私は実際にそれを英語のような API を持つ単純なライブラリに抽出したので、次のように言えます。

type("myUsername").intoThe(username_field);
click(login_button);

私は約 4 つのアクティビティの深さまでテストしましたが、アプローチが機能することに満足していますが、前述のように、完全には把握していないタイミングの問題が時折あるようです。アクティビティ全体をテストする他の方法については、まだ興味があります。

于 2009-11-28T05:22:26.777 に答える
22

Robotium の「Androidアプリケーションの自動ブラックボックステストを、そのままのAndroidインストルメンテーションテストで可能なものよりも大幅に高速かつ簡単にするために作成されたオープンソーステストフレームワーク」をご覧ください。

ホームページ: http
://www.robotium.org/ ソース:http: //github.com/jayway/robotium

Robotiumプロジェクトは私が働いている会社によって維持されていることに注意してください

于 2010-01-26T21:31:35.993 に答える
8

いつでも Robotium を使用できます。Selenium と同様にブラックボックス テストをサポートしますが、Android 向けです。Robotium.orgで見つけることができます

于 2010-01-21T20:30:57.940 に答える
4

主要な自動機能テスト ツールのいくつかについて誰も言及していないことに驚いています。Robotium と比較すると、これらは Java コードを記述する必要がありません。

MonkeyTalk : Gorilla Logic 社が支援するオープンソース ツール。長所: 技術者以外のユーザーにとってより簡単な記録と高レベルのスクリプト言語を提供し、クロスプラットフォーム (iOS を含む) です。これらの利点を要件として考えると、これが最良のソリューションであることがわかりました。また、Javascript を使用してスクリプト言語で実行できる以上のカスタマイズも可能です。

Calabash-Android : Cucumber スタイルの機能のためのオープンソース ツール。長所: ビジネスで読み取り可能なドメイン固有言語である Gherkin 言語で機能を記述します。これにより、ソフトウェアの動作がどのように実装されているかを詳しく説明しなくても記述できます。cucumber-iosでは、iOS で同様のサポートが利用できますが、正確ではありません。バイナリ出力を生成するため、記録機能はそれほど良くありません。

他のいくつかの参照:

于 2013-01-28T19:35:27.747 に答える
3

まず、基本クラスとして「InstrumentationTestCase」ではなく「ActivityInstrumentationTestCase2」を使用します。Robotiumを使用して、複数のアクティビティにわたって定期的にテストしています。ログインアクティビティをジェネリック型(およびコンストラクターへのクラス引数)として指定する必要があることがわかりました。

'ActivityInstrumentationTestCase2'コンストラクターはパッケージ引数を無視し、それを必要としません。パッケージを受け取るコンストラクターは非推奨になりました。

Javadocから: "ActivityInstrumentationTestCase2(String pkg、Class activityClass)このコンストラクターは非推奨です。代わりにActivityInstrumentationTestCase2(Class)を使用してください。"

推奨される基本クラスを使用すると、フレームワークは、アクティビティの開始など、特定の定型文を処理できます。これは、必要に応じて「getActivity()」を呼び出すことで実行されます。

于 2012-05-31T23:30:34.320 に答える
3

Android 用の記録再生ツールを作成し、GitHubで公開しました。構成と使用は簡単で、プログラミングは不要で、実際のデバイス (ルート化する必要はありません) に対して実行され、テストを実行するときにスクリーンショットを自動的に保存します。

于 2011-08-18T19:26:09.747 に答える
2

フレークの待機時間が同期しないようにするには、次のようにします。

final Button btnLogin = (Button) getActivity().findViewById(R.id.button);
Instrumentation instrumentation = getInstrumentation();

// Register we are interested in the authentication activity...
Instrumentation.ActivityMonitor aMonitor = 
        instrumentation.addMonitor(mynextActivity.class.getName(), null, false);

getInstrumentation().runOnMainSync(new Runnable() {
         public void run() {
             btnLogin.performClick();
         }
     });

getInstrumentation().waitForIdleSync();

//check if we got at least one hit on the new activity
assertTrue(getInstrumentation().checkMonitorHit(aMonitor, 1)); 
于 2012-11-25T17:10:15.427 に答える
1

私はほとんど同じことに取り組んでおり、おそらくこの質問に対する受け入れられた回答のバリエーションを使用しますが、解決策を探しているときにCalculuon gitHub)に出くわしました。

于 2011-11-22T02:11:23.250 に答える
0

Monkey ツールのテストを試す

ステップ1:

android studio ターミナルを開きます (ツール -> ターミナルを開く)

ステップ2:

monkey を使用するには、コマンド プロンプトを開き、次のディレクトリに移動します。

 export PATH=$PATH:/home/adt-bundle-linux-x86-20140702/sdk/platform-tools

ステップ 3:

このサルのコマンドを端末に追加して、Enter キーを押します。

エミュレータで魔法を見てください。

adb shell monkey -p com.example.yourpackage -v 500

500 - これは、テストのために送信される頻度カウントまたはイベント数です。

このカウントは変更できます。

さらに参考に、

http://www.tutorialspoint.com/android/android_testing.htm

http://androidtesting.blogspot.in/2012/04/android-testing-with-monkey-tool.html

于 2015-05-20T14:58:58.063 に答える
0

ActivityInstrumentation クラスを使用して複数のアクティビティを実行する別の方法があります。通常の自動化シナリオです。まず、必要なオブジェクトのフォーカスを取得してから、そのサンプル コードのようにシンプルなキーを送信します。

button.requestFocus();
sendKeys(KeyEvent.KEYCODE_ENTER);

唯一のことは、すべての API 呼び出しを理解することです。

于 2009-12-08T06:06:36.357 に答える
0

私は個人的には使用していませんが、ApplicationTestCase はあなたが探しているもののようです。

于 2009-11-19T22:31:31.840 に答える
0

受け入れられたアプローチは、異なる証明書によって署名された、異なるアプリケーションの異なるアクティビティで機能しますか? そうでない場合は、Robotium が同じアプリケーション内でアクティビティをテストするための最良の方法です。

于 2011-04-06T21:52:56.333 に答える