web-dev-qa-db-ja.com

Androidデバイスでアサートを使用できますか?

Assertキーワードを使用してAndroidアプリでアプリを破棄しますエミュレータ上のいくつかのケース、またはテスト中のデバイス。これは可能ですか?

エミュレータは私の主張を無視しているようです。

89
Janusz

埋め込みVMコントロールドキュメント( ソースツリー からの生のHTML、または 適切にフォーマットされた コピー)を参照してください。

基本的に、Dalvik VMは、.dexバイトコードにチェックを実行するコードが含まれている場合でも、デフォルトでアサーションチェックを無視するように設定されています。アサーションのチェックは2つの方法のいずれかでオンになります:

(1)システムプロパティ「debug.assert」を次のように設定することにより:

adb Shell setprop debug.assert 1

これを行った後にアプリを再インストールする限り、意図したとおりに動作することを確認しました。

(2)コマンドライン引数「--enable-assert」をdalvik VMに送信することにより、アプリ開発者ができることではないかもしれません(誰かが私を修正したらここで間違っています)。

基本的に、グローバルに、パッケージレベルで、またはそのレベルでアサーションを有効にするクラスレベルで設定できるフラグがあります。フラグはデフォルトでオフになっており、その結果、アサーションチェックはスキップされます。

サンプルアクティビティに次のコードを記述しました。


public class AssertActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    int x = 2 + 3;
    assert x == 4;
  }
}

このコードの場合、生成されるdalvikバイトコードは(Android 2.3.3)の場合:


// Static constructor for the class
000318:                                        |[000318] com.example.asserttest.AssertActivity.:()V
000328: 1c00 0300                              |0000: const-class v0, Lcom/example/asserttest/AssertActivity; // class@0003
00032c: 6e10 0c00 0000                         |0002: invoke-virtual {v0}, Ljava/lang/Class;.desiredAssertionStatus:()Z // method@000c
000332: 0a00                                   |0005: move-result v0
000334: 3900 0600                              |0006: if-nez v0, 000c // +0006
000338: 1210                                   |0008: const/4 v0, #int 1 // #1
00033a: 6a00 0000                              |0009: sput-boolean v0, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000
00033e: 0e00                                   |000b: return-void
000340: 1200                                   |000c: const/4 v0, #int 0 // #0
000342: 28fc                                   |000d: goto 0009 // -0004


: :


// onCreate() 00035c: |[00035c] com.example.asserttest.AssertActivity.onCreate:(Landroid/os/Bundle;)V 00036c: 6f20 0100 3200 |0000: invoke-super {v2, v3}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0001 000372: 1501 037f |0003: const/high16 v1, #int 2130903040 // #7f03 000376: 6e20 0500 1200 |0005: invoke-virtual {v2, v1}, Lcom/example/asserttest/AssertActivity;.setContentView:(I)V // method@0005 00037c: 1250 |0008: const/4 v0, #int 5 // #5 00037e: 6301 0000 |0009: sget-boolean v1, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000 000382: 3901 0b00 |000b: if-nez v1, 0016 // +000b 000386: 1251 |000d: const/4 v1, #int 5 // #5 000388: 3210 0800 |000e: if-eq v0, v1, 0016 // +0008 00038c: 2201 0c00 |0010: new-instance v1, Ljava/lang/AssertionError; // class@000c 000390: 7010 0b00 0100 |0012: invoke-direct {v1}, Ljava/lang/AssertionError;.:()V // method@000b 000396: 2701 |0015: throw v1 000398: 0e00 |0016: return-void


静的コンストラクターがClassオブジェクトのdesiredAssertionStatusメソッドを呼び出し、クラス全体の変数$ assertionsDisabledを設定する方法に注目してください。また、onCreate()では、Java.lang.AssertionErrorをスローするすべてのコードがコンパイルされますが、その実行は、静的コンストラクターのClassオブジェクトに設定されている$ assertionsDisabledの値に依存することに注意してください。

JUnitのAssertクラスが主に使用されるものであるように見えるため、それを使用するのが安全な方法である可能性があります。 assertキーワードの柔軟性は、開発時にアサーションをオンにして、出荷時にアサーションをオフにし、代わりに正常に失敗する機能です。

お役に立てれば。

145
scorpiodawg

アサーションが有効になっている場合、assertキーワードは、ブール式がAssertionErrorのときに false をスローします。

だから、IMO、最高の代替、特に。あなたがjunitに依存したくない場合は、以下に示すようにAssertionErrorを明示的にスローすることです:

assert x == 0 : "x = " + x;

上記のステートメントの代替は次のとおりです。

Utils._assert(x == 0, "x = " + x);

メソッドは次のように定義されます:

public static void _assert(boolean condition, String message) {
    if (!condition) {
        throw new AssertionError(message);
    }
}

Oracle Java docs 推奨 許容可能な代替としてAssertionErrorをスローします。

プロダクションコードのこれらの呼び出しを削除するようにProguardを構成できると思います。

10
Dheeraj V.S.

「Android in Practice」では、以下を使用することをお勧めします。

$adb Shell setprop dalvik.vm.enableassertions all

この設定が電話機に保持されていない場合は、次のようなプロパティで/data/local.propファイルを作成できます。

dalvik.vm.enableassertions=all
8
marcinj

Googleで問題をチェックアウトするまで、アサーションが機能しなかったことが地獄を悩ませていました...単純なアサーションをあきらめ、junitsアサーションメソッドを使用します。

便宜上、私は使用しています:

import static junit.framework.Assert。*;

静的インポートのため、後で記述できます。

assertTrue(...); Assert.assertTrue(...);の代わりに

5
Ready4Android

JUnitアサート(または他のクラスパス)でコードを出荷する場合は、ProGuard構成オプション 'assumenosideeffects'を使用できます。これにより、削除してもコードに対して何も行われないという前提でクラスパスが削除されます。 。

例えば。

-assumenosideeffects junit.framework.Assert {
*;
}

すべてのテストメソッドを配置する共通のデバッグライブラリがあり、このオプションを使用して、リリースされたアプリからそれを削除します。

これにより、リリースコードで決して使用されない、操作されている文字列の見つけにくい問題も削除されます。たとえば、デバッグログメソッドを作成し、そのメソッドで文字列を記録する前にデバッグモードをチェックする場合、文字列を作成し、メモリを割り当て、メソッドを呼び出しますが、何もしないことを選択します。クラスを削除すると、呼び出しが完全に削除されます。つまり、文字列がメソッド呼び出し内に構築されている限り、それもなくなります。

ただし、ProGuardの一部をチェックせずに行を削除するため、行を削除するだけで本当に安全であることを確認してください。 voidを返すメソッドを削除しても問題ありませんが、削除するものから戻り値を取得する場合は、実際の操作ロジックに使用しないようにしてください。

4
Zulaxia

Junitを削除することに関するZulaxiaの回答に追加するには、ProguardはすでにAndroid SDK/Eclipseの一部であり、次のページで有効にする方法を説明しています。

http://developer.Android.com/guide/developing/tools/proguard.html

また、上記のオプションは、-dontoptimizeフラグを使用するため、最新のデフォルトのproguard構成では機能しません。このフラグは削除する必要があり、最適化の一部は有効になっています。

1
Sean Moore

アサーションを使用できますが、アサーションを確実に使用するには多少の手間がかかります。システムプロパティdebug.assertは信頼できません。問題を参照してください 17569765186786 および 17324

1つの方法は、各assertステートメントをランタイムが処理できるものに変換することです。 Javaコンパイラの前にあるソースプリプロセッサでこれを行います。たとえば、次のステートメントを使用します。

assert x == 0: "Failure message";

デバッグビルドの場合、プリプロセッサは上記をifステートメントに変換します。

{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }

実動ビルドの場合、空のステートメントに対して:

;

これは、実行時ではなく、ビルド時にアサーションを制御することに注意してください(通常の方法)。

既製のプリプロセッサが見つからなかったので、 スクリプト化されたもの です。アサーションを扱う部分を参照してください。コピーするライセンスは here です。

1
Michael Allan

標準のJava assertキーワードを使用します。例:

assert a==b;

これを機能させるには、/ system/build.propに1行追加して、電話を再起動する必要があります。

debug.assert=1

これは、根ざした電話で動作します。 build.propを編集できるファイルマネージャー(X-ploreなど)を使用します。

プラス:ほとんど(すべて?)Android電話はアサーションを無効にして出荷されます。コードが誤ってfalseにアサートされたとしても、アプリは中断またはクラッシュしません。アサーション例外。

0
Pointer Null