テスト可能なコードを書く
この2,3日テストコードの書き方を考えています.ちょっと感じましたが、ここでゆっくり整理します. Mock.mockの英語の意味は模倣、虚偽で、ソフトウェアテストの中で、それは1種のテスト手段と構想を代表します.同僚にmockの基本的な用途と使い方を教えてもらった後、mockをテスト戦略としてもっと正確に説明したと思います(私もテストに関する理論を系統的に勉強したことがありません.ここでもどう言いたいですか).EasyMockのようなクラスライブラリは,この戦略の実現である.この点を説明するのは、別の同僚からMockの紹介を初めて聞いたときにそれを一つのものと解釈したためで、私が知った後、私は物ではなく、被試験類の依存者をシミュレートしてテストの目的を達成する方法だと思います. 抽象クラスについては、単独でテストする必要はありません.実際にはテストもできません.そのinheritorsを直接テストすればいいです. プログラマーは、テスト可能なコードを書くために、テストの技術を理解する必要があります.私は今日自分で2日前に書いた小さなアプリケーションにテストコードを書いて、主にテストの流れを学ぶために、しばらく書いていないで、私が前にいくつかのコードを書いたのはテスト性を備えていないことに気づきました.私は同僚に、このような状況に遭遇したらどうするかと聞いた.彼は、実装コードを変更して、テストコードを書き続けたと言った(私たちは現在TDD開発を行っていないので、テストコードは後期補充されている).だから私は、仕事に戻る以上、実は自分が書いたコードが不合格であることを証明して、考えてみると、もし自分が書いたコードが、ある日自分で測ったのではなく、他人がテストした時、変えられた「面目が全く違う」なら、それは耻ずかしいことではないかと思います.だから必ず本当にテストコードを書いたことがあって、更にテストコードを書くような考えを持ってコードを書いて、あなたのこの一環の品質は合格して、全体の品質と効率はやっと向上します.長い練習と実践を経て、このような考えがコード習慣になったとき、自分が合格したプログラマーだと言う資格がある. 実際にAndroidテストフレームワークに文句を言わなければなりません.本当に使いにくいです.Androidテストapiを使用すると、エラーを使用すると、このフレームワークはtrackの問題を報告するのに役立つ情報をほとんどくれません.さっき、私は何時間もかけて愚かに見える問題を探していました.(参照)http://code.google.com/p/android/issues/detail?id=8501ああ、こんな問題にぶつかって、本当に涙が出た).だから、1.使用するクラスにpublicの無パラメトリックコンストラクタを追加することを覚えておいてください.2.複数のideを開かないで、テストコードを実行してください. Activityのライフサイクルをどのように制御して監視し、テストの目的を達成しますか?Activityの ライフサイクル制御api(余談:ライフサイクルapi,onCreate,onResumeなど、設計モードから見るとTemplate Methodsではないでしょうか).次に、これらのクローンを実装するベースクラスActivityを定義し、クローンapiとActivityの自由なライフサイクルapiを関連付ける(このベースクラスをfacadeにする).Activityをテストする場合は、ベースクラスのクローンapiインタフェース変数にインプリメンテーションインスタンスを注入すればよい.はっきり言わなかったかもしれませんが、コードに説明させます.
次に、テスト環境の初期化中に注入操作を追加します.
MemberAccessorツールクラスの実装を見てみましょう.
注意:注入された変数は必ず静的である.
これはアイデアにすぎず、Activityのテスト性を向上させる.は、インタフェース向けのプログラミングの利点の1つとして、テスト性を向上させる.例えばモックをデザインするときは、安逸でしょう. 命令行の下でテストコード必須命令を実行する:adb shell pm(万悪のgoogleドキュメント、私にtutorialに従って何時間も振り回されても、出てこなかったので、SOの前の答えができました.憎い、#). 命令があって分からない場合は、InstrumentationTestRunnerクラスのdocを見に行くととても役に立ちます.は良好なintent構造を設計し、テスト性を高めることができる.ユニットテスト、Instrumentationテストの場合、intent制御プログラムの流れを使用するのはかなり簡単で、monkeyテストの場合はなおさらです.実は私の最初のdemoの経験から見ると、最もintentを書かないのがactivityのジャンプ制御なので、これは注意しなければならないところかもしれません. //続き
package com.nsworks.testdemo.util;
import android.app.Activity;
import android.os.Bundle;
/**
* The super base activity for all activities, each activity should inherit it.
*/
public class BaseActivity extends Activity {
public interface ActivityLifeCycleController {
public void onCreate(BaseActivity instance, Bundle myCycle);
public void onStart(BaseActivity instance);
public void onResume(BaseActivity instance);
public void onPostResume(BaseActivity instance);
public void onPause(BaseActivity instance);
public void onStop(BaseActivity instance);
public void onDestroy(BaseActivity instance);
}
// Note: this field must be declared static in order to be injected
// in test framework implementations.
private static ActivityLifeCycleController mCycleController;
// Note: Android test framework need each class to have a public constructor
// without any parameters
// I think this is weird, but if a class has not a such constructor will
// cause a failure.
public BaseActivity() {
// Do something
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mCycleController != null) {
mCycleController.onCreate(this, savedInstanceState);
}
}
@Override
protected void onStart() {
super.onStart();
if (mCycleController != null) {
mCycleController.onStart(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mCycleController != null) {
mCycleController.onResume(this);
}
}
@Override
protected void onPostResume() {
super.onPostResume();
if(mCycleController != null) {
mCycleController.onPostResume(this);
}
}
@Override
protected void onPause() {
super.onPause();
if (mCycleController != null) {
mCycleController.onPause(this);
}
}
@Override
protected void onStop() {
super.onStop();
if (mCycleController != null) {
mCycleController.onStop(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mCycleController != null) {
mCycleController.onDestroy(this);
}
}
}
次に、テスト環境の初期化中に注入操作を追加します.
MemberAccessor.searchSuperField(DayActivity.class, "mDbFacade", new MockCTDbFacade());
MemberAccessorツールクラスの実装を見てみましょう.
public static Class<?> searchSuperField(Class<?> target, String fieldName, Object value) throws SecurityException, IllegalArgumentException, IllegalAccessException{
if(target == null)
return null;
if(target.getClass().equals(Object.class))
return null;
Field field = null;
try {
field = target.getDeclaredField(fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException e) {
searchSuperField(target.getSuperclass(), fieldName, value);
}
if(field != null) {
field.set(null, value);
}
return target;
}
注意:注入された変数は必ず静的である.
これはアイデアにすぎず、Activityのテスト性を向上させる.