Чи можу я використовувати assert на пристроях Android?


88

Я хочу використовувати ключове слово Assert у своїх програмах для Android, щоб у деяких випадках знищити мою програму на емуляторі або на моєму пристрої під час тестування. Чи можливо це?

Здається, емулятор просто ігнорує мої твердження.


2
Для АРТ, а не Dalvik см stackoverflow.com/questions/35997703 / ...
Тадей

1
Зауважте, що прийнята відповідь досить оманлива.
зменшення активності

Відповіді:


-7

API надає JUnit Assert .

Ви можете зробити

import static junit.framework.Assert.*;

тепер ви можете використовувати всі функції, такі як assertTrue, assertEquals, assertNull, які надані в рамках junit.

Будьте обережні, щоб не імпортувати фреймворк Junit4 через eclipse, це був би пакет org.junit. Вам потрібно використовувати пакет junit.framework, щоб він працював на пристрої Android або емуляторі.


51
Ну, ОП попросив "assert keyword", який - на відміну від junit.framework.Assert може бути оптимізований JIT. І саме з цієї причини я прийшов сюди. Сподіваюся, деякі інші відповіді будуть кориснішими.
Мартін

27
Я ненавиджу грубість, але це не повинно бути прийнятою відповіддю, оскільки вона не відповідає на запитання (я погоджуюся з коментарем @Martin). Інші відповіді пояснюють, як правильно зробити функцію ключового слова assert, наприклад, запустити "adb shell setprop debug.assert 1"
jfritz42

3
Проголосували проти, оскільки OP запитав про ключове слово assert. @scorpiodawg позначив процес нижче: stackoverflow.com/a/5563637/484261

Відповідь scorpiodawg надійшла лише через рік, тому, мабуть, цю відповідь прийняли лише тому, що ОП з якихось причин відчув себе зобов'язаним позначити відповідь як прийняту. Таке ставлення робить величезну кількість відповідей на ТО або неповними, або відверто жахливими.
async

145

Перегляньте вбудований документ керування віртуальною машиною (необроблений HTML із вихідного дерева або гарно відформатована копія).

В основному, віртуальна машина Dalvik налаштована ігнорувати перевірки тверджень за замовчуванням, навіть якщо код байту .dex містить код для виконання перевірки. Перевірка тверджень включається одним із двох способів:

(1) встановивши системну властивість "debug.assert" через:

adb shell setprop debug.assert 1

який я перевірив, працює за призначенням до тих пір, поки ви перевстановите свою програму після цього, або

(2) надіславши аргумент командного рядка "--enable-assert" на віртуальну машину dalvik, що, можливо, не те, що можуть зробити розробники додатків (хтось виправить мене, якщо я тут помиляюся).

В основному, існує прапор, який можна встановити як глобально, на рівні пакета, так і на рівні класу, який дозволяє твердження на цьому відповідному рівні. За замовчуванням прапор вимкнено, в результаті чого перевірки тверджень пропускаються.

Я написав наступний код у своєму зразку Activity:


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

Зверніть увагу, як статичний конструктор викликає метод desireAssertionStatus для об'єкта Class і встановлює загальнозмінній змінну $ assertionsDisabled; також зауважте, що в onCreate () весь код для викидання java.lang.AssertionError компілюється, але його виконання залежить від значення $ assertionsDisabled, яке встановлено для об'єкта Class у статичному конструкторі.

Схоже, що переважно використовується клас Assert JUnit, тому, скоріше за все, це безпечне рішення. Гнучкість ключового слова assert - це можливість увімкнути твердження під час розробки та вимкнути їх для розвантажувальних бітів і замість цього витончено провалитися.

Сподіваюся, це допомагає.


Здається, Google видалив доступне для перегляду джерело (я бачив посилання на це у відповідях на інші запитання тут). Найкраще - або отримати джерело, або спробувати знайти це в пошуковій системі. Шукайте "dalvik / embedded-vm-control.html". Ось одне місце, де воно є: assembla.com/code/android-gb-for-sharp-is01/git/nodes/dalvik/… . Сподіваюся, це допомагає.
scorpiodawg

Дуже корисно, дякую. Однак мене бентежить різниця, зроблена в останньому абзаці. Ми обговорюємо два типи тверджень: перший - це методи пакета JUnit Assert, такі як assertNotNull (), а другий - ключове слово мови "assert" мови Java. Ваша відповідь стосується обох? Наприклад, якщо я, import static junit.framework.Assert.*а потім я використовую один із його методів, наприклад assertNotNull("It's null!", someObject);, чи відключається це твердження у відправних бітах?
Джеффро

1
Привіт Джеффро! Ключове слово assert, з іншого боку, вбудовано в мову. Сподіваюся, це допомагає.
scorpiodawg

3
Чи є спосіб зробити adb shell setprop debug.assert 1в Eclipse?
Pacerier

1
Твердження також можна зробити з терміналу, запущеного на пристрої, якщо ви кореневий. Спочатку 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 на практиці" пропонується використовувати:

$adb shell setprop dalvik.vm.enableassertions all

якщо ці налаштування не зберігаються на вашому телефоні, ви можете створити файл /data/local.prop із такими властивостями, як:

dalvik.vm.enableassertions=all

Відповідно до stackoverflow.com/a/18556839/2004714 , можливо, вам доведеться переконатися, що файл зроблено лише для читання ( chmod 644).
Пауло

5

Це, на біс, мене викрикувало, що мої твердження не працювали, поки я не перевірив проблему в google ... Я відмовився від простих тверджень і піду з методами твердження junits.

Для зручності я використовую:

імпортувати статичний junit.framework.Assert. *;

Через статичний імпорт я згодом можу написати:

assertTrue (...); замість Assert.assertTrue (...);


4

Якщо ви стурбовані кодом доставки із твердженнями JUnit (або будь-яким іншим шляхом до класу), ви можете скористатися параметром конфігурації ProGuard 'pretumenosideeffects', який видалить шлях до класу, припускаючи, що його видалення нічого не робить для коду .

Напр.

-assumenosideeffects junit.framework.Assert {
*;
}

У мене є загальна бібліотека налагодження, в яку я вкладаю всі свої методи тестування, а потім використовую цю опцію, щоб видалити її з моїх випущених програм.

Це також усуває важко помітну проблему рядків, якими маніпулюють, які ніколи не використовуються в коді випуску. Наприклад, якщо ви пишете метод журналу налагодження, і в цьому методі ви перевіряєте режим налагодження перед реєстрацією рядка, ви все ще будуєте рядок, виділяєте пам'ять, викликаєте метод, але потім вибираєте нічого не робити. Видалення класу потім повністю видаляє виклики, тобто, поки ваш рядок побудований всередині виклику методу, він також зникає.

Переконайтеся, що по-справжньому безпечно просто зачищати рядки, проте це робиться без перевірки з боку ProGuard. Видалення будь-якого методу повернення порожнечі буде добре, однак, якщо ви берете будь-які повернені значення з того, що ви видаляєте, переконайтеся, що не використовуєте їх для фактичної операційної логіки.


1
Я думаю, що правильний синтаксис буде таким:-assumenosideeffects class junit.framework.Assert { *; }
Pooks

Заплутана відповідь. Згадана команда викликає помилку proguard. Команда, виправлена ​​Pooks, все ще не видаляє твердження з бінарного файлу dex.
Нуль покажчика

У мене така сама проблема @PointerNull. стверджувати звичай не видаляється.
Махді

3

Ви можете використовувати твердження, але для їх надійного використання потрібна певна робота. Властивість системи debug.assertненадійна; див. випуски 175697 , 65183 , 36786 та 17324 .

Одним із методів є переклад кожного assertвисловлювання на те, з чим може впоратися будь-яка програма виконання. Зробіть це за допомогою препроцесора джерела перед компілятором Java. Для прикладу візьмемо таке твердження:

assert x == 0: "Failure message";

Для побудови налагодження ваш препроцесор перекладе вищезазначене ifтвердження:

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

Для виробничої збірки до порожнього виписки:

;

Зверніть увагу, що це контролюватиме твердження під час побудови, на відміну від часу виконання (звичайна практика).

Я не міг знайти готовий препроцесор, тому написав його . Див. Частину, що стосується тверджень. Ліцензія на копіювання тут .


1

Щоб додати відповідь Zulaxia на видалення Junit - Proguard вже є частиною Android SDK / Eclipse, і на наступній сторінці ви дізнаєтесь, як його увімкнути.

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

Також вищезазначене не працюватиме з останньою конфігурацією proguard за замовчуванням, оскільки воно використовує прапорець -dontoptimize, який потрібно вийняти та ввімкнути деякі оптимізації.


0

Використовуйте стандартне ключове слово Java assert , наприклад:

assert a==b;

Щоб це працювало, потрібно додати один рядок до /system/build.prop і перезавантажити телефон:

debug.assert=1

Це буде працювати на кореневому телефоні. Використовуйте якийсь файловий менеджер, здатний редагувати build.prop (наприклад, X-plore).

Плюси: більшість (усіх?) Телефонів Android постачаються з відключеними твердженнями. Навіть якщо ваш код випадково встановить значення false, додаток не перериватиметься та не працюватиме. Однак на вашому пристрої розробки ви отримаєте твердження про виняток.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.