Androidアプリをテストします。

18413 ワード

Androidは、ユニットテスト、フレームテスト、ui自動化テストなど、さまざまなレベルからアプリケーションを全面的にテストすることができます。Androidテストアーキテクチャを図に示す。
転載は出典を明記してください。http://blog.csdn.net/qinjunni2014/article/details/45854305
JUnit構築テスト
すべてのAndroidテストはJUnitに基づいています。Androidアプリを起動しないテストを構築することができます。
import junit.framework.TestCase;

/** * Created by Junli on 5/19/15. */
public class UnitTest extends TestCase {

    public void test() throws Exception{
        final int expected = 1;
        final int reality = 5;
        assertEquals(expected, reality);
    }
}
TestCaseから継承すればJUnitベースのユニットテストが構築できます。testの先頭の関数であれば、テストキューに参加されます。テストにおいて、Asssertライブラリの関数を使って、astertEqualsで等しいテストを行います。しかし、このテストはdeviceでしかテストできません。ローカルテストができないと、Stubを抛り出します。Not implemented"exception。実際には、Androidのテストはすべてdeviceでしか走れません。ある第三者テストフレームを除いて、Robolectricのようなものがあります。
Instrument紹介
通常、Androidアプリケーションでは、すべてのコンポーネントのライフサイクルがシステムで決定されます。例えば、ActivityのonCreate、ResoResume、onPauseなどの方法の呼び出しはシステム内で決定されます。開発者はシステムアプリを通じて直接に呼び出すことはできませんが、Instructionを通じて私たちはそれを行うことができます。また、Instruumentationでは、アプリケーションにイベントを送ることもできます。
Activityユニット試験
Activityをテストする時、私達はActivityUnity TestCaseから受け継ぐ必要があります。まず簡単なActivityを書きます。

public class MainActivity extends Activity {
    EditText edit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        edit = (EditText) findViewById(R.id.edit);
    }

    public void onClick(View v){
        Intent intent = new Intent(this, SecondActivity.class);
        intent.putExtra("text", edit.getText());
        startActivity(intent);
    }
}
レイアウトファイルは以下の通りです。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Start"
        android:layout_centerInParent="true"
        android:id="@+id/btn"/>

    <EditText
        android:layout_width="250dp"
        android:layout_height="50dp"
        android:id="@+id/edit"
        android:layout_marginTop="15dp"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/btn"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/btn"
        android:layout_marginTop="10dp"/>

</RelativeLayout> 
レイアウトファイルには、Btton、EditText、Text Viewが含まれています。簡単なテストをします。
public class MainActivityUnitTest extends ActivityUnitTestCase<MainActivity> {

    private int buttonId;
    private MainActivity activity;

    public MainActivityUnitTest() {
        super(MainActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        Intent intent = new Intent(getInstrumentation().getTargetContext(), MainActivity.class);
        startActivity(intent, null, null);
        activity = getActivity();
    }

    public void testLayout() {
        buttonId = R.id.btn;
        assertNotNull(activity.findViewById(buttonId));
        Button view = (Button) activity.findViewById(buttonId);
        assertEquals("Incorrect label of the button", "Start", view.getText());
    }
}
私たちはsetup関数で簡単なテストをします。私たちはまず私たちのMainActivityを起動して、GEtActivity方法でActivityの引用をもらいます。testLayout関数では、ActivityのfindView ById法によってviewを得ることができます。astert NotNull方法によってテストします。その後、astertEquals関数を呼び出して、buttonのtextが正しいかどうかを決定します。
ActivityUnity TestCaseはactivityのレイアウトをチェックし、他のactivityを起動した時のintentをチェックすることを許可します。このintentはAndroidシステムに送信されません。でも、get StartTectivityIntentを呼び出してそれを入手し、テストします。ActivityUnity TestCaseにおけるすべてのテスト方法は、個々のContectで実行されますので、setupでstartActivityをアクティブに起動しなければなりません。
public void testIntent()
{
    buttonId = R.id.btn;
    assertNotNull(activity.findViewById(buttonId));
    Button view = (Button) activity.findViewById(buttonId);
    view.performClick();

    Intent intent = getStartedActivityIntent();
    assertNotNull(intent);//  intent  null
    String data = intent.getExtras().getString("URL");
    //  URL    
    assertEquals("http://blog.csdn.net/qinjunni2014", data);
}
Activity機能テスト
ActivityUnit TestCaseの機能に制限されています。特に複雑な機能をテストすることはできません。例えば、他のアプリケーションコンポーネントと対話して、イベント処理を送信することなどです。しかし、これらの機能のテストを実現するには、ActivityInstructionation TestCase 2を引き継ぐだけでいいです。実例を通して、このクラスはどのようなテストができますか?
//         MainActivity    
public class MainActivityFunctionalTest extends ActivityInstrumentationTestCase2<MainActivity> {

    private MainActivity activity;
    private EditText editText;
    private TextView textView;

    public MainActivityFunctionalTest() {
        super(MainActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        setActivityInitialTouchMode(true);
        activity = getActivity();

        editText = (EditText) activity.findViewById(R.id.edit);
        textView = (TextView) activity.findViewById(R.id.text);
    }

    public void testStartSecondActivity(){
        Instrumentation.ActivityMonitor monitor =
                getInstrumentation().addMonitor(SecondActivity.class.getName(),null,false);

        Button view = (Button) activity.findViewById(R.id.btn);
        TouchUtils.clickView(this, view);

        SecondActivity startedActivity = (SecondActivity) monitor.waitForActivityWithTimeout(2000);
        assertNotNull("ReceiverActivity is null", startedActivity);
        assertEquals("Monitor for ReceiverActivity has not been called",
                1, monitor.getHits());


        TextView textView = (TextView) startedActivity.findViewById(R.id.resultText);
        ViewAsserts.assertOnScreen(startedActivity.getWindow().getDecorView(), textView);

        assertEquals("Text incorrect", "Started", textView.getText().toString());

        this.sendKeys(KeyEvent.KEYCODE_BACK);

        TouchUtils.clickView(this, view);
    }
}
私たちはsetup関数において、startActivityを積極的に起動していないことに気づきました。Unit TestCaseとは違って、このクラスは本物のAndroidシステムアーキテクチャを利用して、getActivityでこのactivityを生成します。
testStartSecondActivity関数は主にSecondActivityを起動する過程をテストします。ここでActivityMonitorを使って、あるタイプのIntentを監視します。activityが起動されると、monitorを検査します。intentがマッチングすれば、monitorのhit countが増加します。TouchUtisを通じてviewをクリックすることができます。monitor.waitForActivity WithTimeoutは、タイムアウトまたはmonitor監視に適合するターゲットactivityが開始されるまで、2000 ms待つことができます。View Assserts.astert OnScreenは私達のviewがスクリーンにあるかどうかをテストできますが、私達はactivityのDecorViewをrootとして伝えます。また、sendKeysを呼び出してActivityにkeyEventイベントを送ることもできます。
非同期タスクをテスト
私たちは一例で分析します。
public class AsyncTaskActivity extends Activity implements View.OnClickListener {

    Button button;
    private IJobListener listener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);

        button = (Button) findViewById(R.id.btn);
        button.setOnClickListener(this);
    }

    public static interface IJobListener {
        void executionDone();
    }

    public void setListener(IJobListener listener) {
        this.listener = listener;
    }

    @Override
    public void onClick(View v) {
        if(v == button){
            myTask.execute();
        }
    }

    final AsyncTask<String, Void, String> myTask = new AsyncTask<String, Void, String>() {


        @Override
        protected String doInBackground(String... arg0) {
            return "Long running stuff";
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if (listener != null) {
                listener.executionDone();
            }
        }
    };
}
buttonをクリックすると、AyncTaskが実行されます。タスクが完了したら。戻ってlistenerのexecution Duneを呼び出して、私達はどのようにこのタスクをテストしましたか?
public class AsyncTaskTest extends ActivityUnitTestCase<AsyncTaskActivity> {

    AsyncTaskActivity activity;
    Button btn;

    public AsyncTaskTest() {
        super(AsyncTaskActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        Intent intent = new Intent(getInstrumentation().getTargetContext(),
                AsyncTaskActivity.class);
        startActivity(intent,null, null);
        activity = getActivity();

        btn = (Button) activity.findViewById(R.id.btn);
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    public void testAsyncTask() throws Throwable
    {
        //     count 1 CountDownLatch
        final CountDownLatch latch = new CountDownLatch(1);

        //      , latch count  
        activity.setListener(new AsyncTaskActivity.IJobListener() {
            @Override
            public void executionDone() {
                latch.countDown();
            }
        });
        //  button,    
        getInstrumentation().runOnMainSync(new Runnable() {
            @Override
            public void run() {
                btn.performClick();
            }
        });
        //          ,    
        boolean await = latch.await(30, TimeUnit.SECONDS);

        assertTrue(await);
    }
}
このように、手順外タスクが指定された時間内に実行されたかどうかは、latchで判断できます。
モンキーを使ってストレステストを行います。
Monkeyはかわいい猿です。私たちはユーザーのクリックイベントを真似して、ランダムに一定数のイベントフローを生成します。例えば、クリック、スライドなど他のジェスチャーで操作します。基本的な使い方は:
$adb shell mokey[options]
Monkeyは多くのオプションを提供していますが、大体四つの種類に分けられます。
  • 基本構成オプション、例えば生成されたイベントの数
  • 操作タイプ制限オプション、たとえば、あるpackageのアプリケーションに対するテストの実行を制限する
  • イベントタイプと比例
  • デバッグオプション
  • たとえば、comp.junli.testというアプリをテストしたいです。イベントの数は1000で、詳細情報を出力して、activityの切り替えを含みます。その上あれらのシステムのレベルのcontrolkey事件を実行しないで、例えばhome、back、volume control、私達はこのようにすることができます。
    adb shell mokey-p comp.junli.test-v 1500–pct-sys 1,000
    -p指定のパッケージ名、-v指定の出力情報レベル、-pct-sys指定のシステムレベルイベントのパーセンテージ、最後の1000の代表は私達がランダムイベントを1000配布したいです。
    もっとMonkeyの情報を参考にしてください。http://developer.android.com/tools/help/monkey.html