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


88

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

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


2
DalvikではなくARTについては、stackoverflow.com
questions / 35997703 /…を

受け入れられた答えはかなり誤解を招くことに注意してください。
活動の削減

回答:


-7

APIはJUnitアサートを提供します

できるよ

import static junit.framework.Assert.*;

これで、junitフレームワークで提供されるassertTrue、assertEquals、assertNullなどのすべての関数を使用できます。

Junit4フレームワークをEclipseからインポートしないように注意してください。これはorg.junitパッケージになります。Androidデバイスまたはエミュレーターで動作させるには、junit.frameworkパッケージを使用する必要があります。


51
まあ、OPはjass.framework.Assertとは異なり、JITによって最適化できる「キーワードのアサート」を要求しました。そして、まさにこの理由で私はここに来ました。他の回答のいくつかがもっと役立つことを願っています。
マーティン

27
私は失礼な言い方をしたくありませんが、質問に答えないため、これは受け入れられる答えにはなりません(@Martinのコメントに同意します)。他の回答は、assertキーワードを適切に機能させる方法を説明しています。たとえば、「adb shell setprop debug.assert 1」を実行します
jfritz42

3
OPがassertキーワードについて質問したため、反対票が投じられました。@scorpiodawgは以下のプロセスの概要を示しています:stackoverflow.com/a/5563637/484261

scorpiodawgの回答は1年後になってきたので、OPが何らかの理由で回答を承認済みとしてマークする義務があると感じたためにのみ、この回答が承認されたと思います。この態度は、SOに対する膨大な数の回答を不完全または完全にひどいものにします。
非同期2014年

145

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

基本的に、.dexバイトコードにチェックを実行するコードが含まれていても、Dalvik VMはデフォルトでアサーションチェックを無視するように設定されています。アサーションのチェックは、次の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キーワードの柔軟性は、開発時にアサーションをオンにし、出荷段階でオフにして、代わりに正常に失敗する機能です。

お役に立てれば。


Googleが参照可能なソースを削除したようです(他の質問への回答でこれへの言及を見ました)。あなたの最善の策は、ソースを入手するか、これを検索エンジンで調べようとすることです。「dalvik / embedded-vm-control.html」を検索してください。これがある場所の1つは、assembla.com / code / android-gb-for-sharp-is01 / git / nodes / dalvik / です。お役に立てれば。
scorpiodawg

とても便利です、ありがとうございます。しかし、私は最後から2番目の段落で行われた区別に混乱しています。ここでは、2種類のアサートについて説明します。1つはassertNotNull()のようなJUnit Assertパッケージのメソッドで、もう1つはJava言語の「assert」キーワードです。あなたの答えは両方に当てはまりますか?たとえば、私import static junit.framework.Assert.*がそのメソッドの1つを使用している場合assertNotNull("It's null!", someObject);、このアサーションは出荷ビットでオフになっていますか?
ジェフロ

1
こんにちは、ジェフロ、私はそうは思いません-junit.framework.Assertは、入力条件がfalseであることが判明したときに例外をスローするクラスです。一方、assertキーワードは言語に組み込まれています。お役に立てれば。
scorpiodawg

3
adb shell setprop debug.assert 1Eclipseで行う方法はありますか?
パセリエ2012年

1
rootである場合、アサーションはデバイスで実行されているターミナルからも実行できます。最初にsu、次にsetprop debug.assert 1。逆アセンブルしたコードは、リリースビルド(stackoverflow.com/a/5590378/506073)に残ります。javacコンパイラーがアサーションを発行しないように指示できるとは思わないので、なんらかの方法で除去する必要があります。そのための簡単な解決策は、キーワードassertを独自の関数にラップして、proguardが削除できるようにすることです。
ahcox

10

アサーションが有効になって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ドキュメントでAssertionError、許容可能な代替としてをスローすることを推奨しています。

量産コードのこれらの呼び出しを取り除くようにProguardを構成できると思います。


しかし、どのようにアサーションを有効にしますか?Android Studioで?
SMBiggs

8

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

$adb shell setprop dalvik.vm.enableassertions all

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

dalvik.vm.enableassertions=all

パーstackoverflow.com/a/18556839/2004714、あなたも必ず、ファイルが読み取り専用にされていることを確認する必要があるかもしれません(chmod 644)。
パウロ

5

グーグルで問題をチェックアウトするまで、アサーションが機能しなかったのは私を驚かせていました...単純なアサーションをあきらめ、junitsアサーションメソッドを使用します。

便宜上、私は以下を使用しています。

import static junit.framework.Assert。*;

静的インポートのため、後で書くことができます:

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


4

JUnitアサート(または他のクラスパス)を含むコードの配布に懸念がある場合は、ProGuard構成オプション 'assumenosideeffects'を使用できます。 。

例えば。

-assumenosideeffects junit.framework.Assert {
*;
}

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

これにより、リリースコードでは使用されない操作されている文字列の特定が困難な問題も解消されます。たとえば、デバッグログメソッドを記述し、そのメソッドで文字列をログに記録する前にデバッグモードを確認する場合、文字列を作成し、メモリを割り当て、メソッドを呼び出しますが、何もしないことを選択します。クラスを取り除くと、呼び出しが完全に削除されます。つまり、文字列がメソッド呼び出し内で作成されている限り、文字列も削除されます。

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


1
私は、適切な構文があることだと思う:-assumenosideeffects class junit.framework.Assert { *; }
Pooks

混乱する答え。言及されたコマンドは、プロガードエラーを引き起こします。Pooksによって修正されたコマンドは、バイナリdexファイルからアサーションを削除しません。
ポインタヌル2013

私は同じ問題@PointerNullを持っています。削除されないと主張する。
Mahdi

3

アサーションを使用できますが、アサーションを確実に使用するにはいくつかの作業が必要です。システムプロパティdebug.assertは信頼できません。問題参照1756976518336786および17324を

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

assert x == 0: "Failure message";

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

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

本番ビルドの場合、空のステートメントに:

;

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

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


1

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

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

また、上記の例では、-dontoptimizeフラグを使用する必要があるため、最新のデフォルトのプロガード構成では機能せず、一部の最適化がオンになっています。


0

たとえば、標準のJava アサートキーワードを使用します。

assert a==b;

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

debug.assert=1

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

プラス:ほとんど(すべて?)のAndroidスマートフォンはアサーションを無効にして出荷されます。コードが誤ってfalseにアサートされた場合でも、アプリは中断またはクラッシュしません。ただし、開発デバイスではアサーション例外が発生します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.