Bisakah saya menggunakan assert di perangkat Android?

88

Saya ingin menggunakan kata kunci Assert di aplikasi android saya untuk menghancurkan aplikasi saya dalam beberapa kasus di emulator, atau perangkat saya selama pengujian. Apakah ini mungkin?

Sepertinya emulator mengabaikan pernyataan saya.

Janusz
sumber
2
Untuk ART, daripada Dalvik, lihat stackoverflow.com/questions/35997703/…
fadden
1
Perhatikan bahwa jawaban yang diterima cukup menyesatkan.
mengurangi aktivitas

Jawaban:

-7

API menyediakan JUnit Assert .

Anda dapat melakukan

import static junit.framework.Assert.*;

sekarang Anda dapat menggunakan semua fungsi seperti assertTrue, assertEquals, assertNull yang disediakan dalam kerangka junit.

Berhati-hatilah untuk tidak mengimpor kerangka kerja Junit4 melalui eclipse, yang akan menjadi paket org.junit. Anda harus menggunakan paket junit.framework agar dapat berfungsi di perangkat android atau emulator.

JRL
sumber
51
Nah OP meminta "kata kunci assert" yang - tidak seperti junit.framework.Assert dapat dioptimalkan oleh JIT. Dan untuk alasan inilah saya datang ke sini. Semoga beberapa jawaban lain akan lebih membantu.
Martin
27
Saya benci bersikap kasar tetapi ini seharusnya tidak menjadi jawaban yang diterima karena tidak menjawab pertanyaan (saya setuju dengan komentar @Martin). Jawaban lain menjelaskan cara membuat kata kunci assert berfungsi dengan benar, mis. Jalankan "adb shell setprop debug.assert 1"
jfritz42
3
Tidak dipilih karena OP bertanya tentang kata kunci assert. @scorpiodawg telah menguraikan proses di bawah ini: stackoverflow.com/a/5563637/484261
jawaban scorpiodawg datang hanya setahun kemudian, jadi saya kira jawaban ini diterima hanya karena OP, untuk beberapa alasan, merasa berkewajiban untuk menandai jawaban sebagai diterima. Sikap ini membuat sejumlah besar jawaban tentang SO tidak lengkap atau sangat buruk.
async
145

Lihat dokumen Kontrol VM Tertanam (HTML mentah dari pohon sumber , atau salinan yang diformat dengan baik ).

Pada dasarnya, VM Dalvik diatur untuk mengabaikan pemeriksaan pernyataan secara default, meskipun kode byte .dex menyertakan kode untuk melakukan pemeriksaan. Memeriksa pernyataan diaktifkan dengan salah satu dari dua cara berikut:

(1) dengan menyetel properti sistem "debug.assert" melalui:

adb shell setprop debug.assert 1

yang saya verifikasi berfungsi selama Anda memasang ulang aplikasi setelah melakukan ini, atau

(2) dengan mengirimkan argumen baris perintah "--enable-assert" ke VM dalvik yang mungkin tidak dapat dilakukan oleh pengembang aplikasi (ada yang mengoreksi saya jika saya salah di sini).

Pada dasarnya, ada sebuah flag yang dapat disetel baik secara global, pada tingkat paket, atau pada tingkat kelas yang memungkinkan pernyataan pada tingkat yang bersangkutan. Bendera dinonaktifkan secara default, akibatnya pemeriksaan pernyataan dilewati.

Saya menulis kode berikut dalam Contoh Aktivitas saya:


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;
  }
}

Untuk kode ini, kode byte dalvik yang dihasilkan adalah (untuk 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

Perhatikan bagaimana konstruktor statis memanggil metode yang diinginkanAssertionStatus pada objek Kelas dan menyetel variabel seluruh kelas $ assertionsDisabled; juga perhatikan bahwa di onCreate (), semua kode untuk melempar java.lang.AssertionError dikompilasi, tetapi eksekusinya bergantung pada nilai $ assertionsDisabled yang disetel untuk objek Kelas di konstruktor statis.

Tampaknya kelas Assert JUnit adalah yang paling banyak digunakan, jadi kemungkinan besar aman untuk menggunakannya. Fleksibilitas kata kunci assert adalah kemampuan untuk mengaktifkan pernyataan pada waktu pengembangan dan menonaktifkannya untuk pengiriman bit dan malah gagal dengan baik.

Semoga ini membantu.

scorpiodawg
sumber
Tampaknya Google telah menghapus sumber yang dapat dijelajahi (saya melihat referensi ini dalam jawaban atas pertanyaan lain di sini). Taruhan terbaik Anda adalah mendapatkan sumbernya, atau mencoba mencarinya di mesin pencari. Cari "dalvik / embedded-vm-control.html". Inilah satu tempat yang memilikinya: assembla.com/code/android-gb-for-sharp-is01/git/nodes/dalvik/… . Semoga ini membantu.
scorpiodawg
Sangat bermanfaat, terima kasih. Saya bingung dengan perbedaan yang dibuat di paragraf kedua hingga terakhir. Kami membahas dua jenis asserts: Yang pertama adalah metode paket JUnit Assert seperti assertNotNull (), dan yang kedua adalah kata kunci 'assert' bahasa Java. Apakah jawaban Anda berlaku untuk keduanya? Misalnya, jika saya import static junit.framework.Assert.*dan kemudian saya menggunakan salah satu metodenya, seperti assertNotNull("It's null!", someObject);, apakah pernyataan ini dinonaktifkan dalam bit pengiriman?
Jeffro
1
Hai Jeffro, saya tidak percaya begitu - junit.framework.Assert hanyalah sebuah kelas yang mengeluarkan pengecualian ketika kondisi input ternyata salah. Kata kunci assert di sisi lain dibangun ke dalam bahasa. Semoga ini membantu.
scorpiodawg
3
Apakah ada cara yang dapat dilakukan adb shell setprop debug.assert 1di Eclipse?
Pacerier
1
Penegasan juga dapat dilakukan dari terminal yang berjalan di perangkat jika Anda root. Pertama su, lalu setprop debug.assert 1. Perhatikan bahwa kode yang Anda tunjukkan dibongkar akan tetap dalam versi rilis ( stackoverflow.com/a/5590378/506073 ). Saya tidak percaya kompiler javac dapat diberitahu untuk tidak mengeluarkan pernyataan sehingga mereka perlu dilucuti. Solusi sederhana untuk itu adalah membungkus kata kunci yang menegaskan dalam fungsi Anda sendiri yang dapat dihapus oleh proguard untuk Anda.
ahcox
10

Saat pernyataan diaktifkan, assertkata kunci hanya melempar AssertionErrorketika ekspresi boolean adalah false.

Jadi IMO, alternatif terbaik, esp. Jika Anda menolak untuk bergantung pada junit, adalah dengan melemparkan secara AssertionErroreksplisit seperti yang ditunjukkan di bawah ini:

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

Alternatif dari pernyataan di atas adalah:

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

Dimana metode tersebut didefinisikan sebagai:

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

Dokumen java Oracle merekomendasikan untuk melempar AssertionErrorsebagai alternatif yang dapat diterima.

Saya kira Anda dapat mengkonfigurasi Proguard untuk menghapus panggilan ini untuk kode produksi.

Dheeraj Vepakomma
sumber
Tapi bagaimana Anda mengaktifkan pernyataan? Menggunakan Android Studio?
SMBiggs
8

Dalam "Android in Practice", disarankan untuk menggunakan:

$adb shell setprop dalvik.vm.enableassertions all

jika pengaturan ini tidak bertahan di ponsel Anda, maka Anda dapat membuat file /data/local.prop dengan properti seperti:

dalvik.vm.enableassertions=all
marcinj
sumber
Sesuai stackoverflow.com/a/18556839/2004714 , Anda mungkin juga perlu memastikan bahwa file tersebut dibuat hanya untuk dibaca ( chmod 644).
Paulo
5

Itu mengganggu saya, bahwa pernyataan saya tidak berhasil, sampai saya memeriksa masalah di google ... Saya menyerah pada pernyataan sederhana dan akan menggunakan metode pernyataan junits.

Untuk tujuan kenyamanan saya menggunakan:

impor junit.framework.Assert statis. *;

Karena impor statis saya nanti dapat menulis:

assertTrue (...); bukannya Assert.assertTrue (...);

Ready4Android
sumber
4

Jika Anda khawatir tentang kode pengiriman dengan pernyataan JUnit di (atau jalur kelas lainnya), Anda dapat menggunakan opsi konfigurasi ProGuard 'assumenosideeffects', yang akan menghapus jalur kelas dengan asumsi bahwa menghapusnya tidak berpengaruh pada kode .

Misalnya.

-assumenosideeffects junit.framework.Assert {
*;
}

Saya memiliki pustaka debug umum tempat saya memasukkan semua metode pengujian saya, dan kemudian menggunakan opsi ini untuk menghapusnya dari aplikasi yang saya rilis.

Ini juga menghilangkan masalah sulit ditemukan dari string yang dimanipulasi yang tidak pernah digunakan dalam kode rilis. Misalnya jika Anda menulis metode log debug, dan dalam metode itu Anda memeriksa mode debug sebelum mencatat string, Anda masih membuat string, mengalokasikan memori, memanggil metode tersebut, tetapi kemudian memilih untuk tidak melakukan apa-apa. Melucuti kelas kemudian menghapus panggilan sepenuhnya, yang berarti selama string Anda dibangun di dalam pemanggilan metode, itu juga hilang.

Namun, pastikan benar-benar aman untuk hanya menghapus garis, karena ini dilakukan tanpa memeriksa bagian ProGuard. Menghapus metode pengembalian kosong akan baik-baik saja, namun jika Anda mengambil nilai pengembalian apa pun dari apa pun yang Anda hapus, pastikan Anda tidak menggunakannya untuk logika operasional yang sebenarnya.

Zulaksia
sumber
1
Saya pikir sintaks yang tepat adalah:-assumenosideeffects class junit.framework.Assert { *; }
Pooks
Jawaban yang membingungkan. Perintah yang disebutkan menyebabkan kesalahan proguard. Perintah yang dikoreksi oleh Pooks masih tidak menghapus pernyataan dari file dex biner.
Pointer Null
Saya memiliki masalah yang sama @PointerNull. menegaskan tidak akan dihapus.
Mahdi
3

Anda dapat menggunakan pernyataan, tetapi perlu beberapa upaya untuk menggunakannya dengan andal. Properti sistem debug.asserttidak dapat diandalkan; lihat masalah 175697 , 65183 , 36786 dan 17324 .

Salah satu metode adalah menerjemahkan setiap assertpernyataan menjadi sesuatu yang dapat ditangani oleh runtime apa pun. Lakukan ini dengan preprocessor sumber di depan compiler Java. Misalnya, ambil pernyataan ini:

assert x == 0: "Failure message";

Untuk build debug, preprocessor Anda akan menerjemahkan pernyataan di atas ke if:

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

Untuk produksi build, ke pernyataan kosong:

;

Perhatikan bahwa ini akan mengontrol pernyataan pada waktu pembuatan, sebagai kebalikan dari waktu berjalan (praktik biasa).

Saya tidak dapat menemukan preprocessor yang sudah jadi, jadi saya membuat skrip . Lihat bagian berurusan dengan pernyataan. Lisensi untuk menyalin ada di sini .

Michael Allan
sumber
1

Untuk menambah jawaban Zulaxia tentang menghapus Junit - Proguard sudah menjadi bagian dari Android SDK / Eclipse dan halaman berikut memberi tahu Anda cara mengaktifkannya.

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

Juga di atas tidak akan berfungsi dengan konfigurasi proguard default terbaru karena menggunakan flag -dontoptimize yang harus dihilangkan dan beberapa pengoptimalan dihidupkan.

Sean Moore
sumber
0

Gunakan kata kunci pernyataan Java standar , misalnya:

assert a==b;

Agar ini berfungsi, Anda harus menambahkan satu baris ke /system/build.prop, dan reboot ponsel:

debug.assert=1

Ini akan berfungsi pada ponsel yang di-rooting. Gunakan beberapa pengelola file yang mampu mengedit build.prop (mis. X-plore).

Plus: sebagian besar (semua?) Ponsel Android dikirimkan dengan pernyataan dinonaktifkan. Meskipun kode Anda secara tidak sengaja menyatakan sebagai salah, aplikasi tidak akan mengganggu atau crash. Namun, pada perangkat pengembangan Anda, Anda akan mendapatkan pengecualian pernyataan.

Pointer Null
sumber