Я хочу використовувати ключове слово Assert у своїх програмах для Android, щоб у деяких випадках знищити мою програму на емуляторі або на моєму пристрої під час тестування. Чи можливо це?
Здається, емулятор просто ігнорує мої твердження.
Я хочу використовувати ключове слово Assert у своїх програмах для Android, щоб у деяких випадках знищити мою програму на емуляторі або на моєму пристрої під час тестування. Чи можливо це?
Здається, емулятор просто ігнорує мої твердження.
Відповіді:
API надає JUnit Assert .
Ви можете зробити
import static junit.framework.Assert.*;
тепер ви можете використовувати всі функції, такі як assertTrue, assertEquals, assertNull, які надані в рамках junit.
Будьте обережні, щоб не імпортувати фреймворк Junit4 через eclipse, це був би пакет org.junit. Вам потрібно використовувати пакет junit.framework, щоб він працював на пристрої Android або емуляторі.
Перегляньте вбудований документ керування віртуальною машиною (необроблений 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 - це можливість увімкнути твердження під час розробки та вимкнути їх для розвантажувальних бітів і замість цього витончено провалитися.
Сподіваюся, це допомагає.
import static junit.framework.Assert.*
а потім я використовую один із його методів, наприклад assertNotNull("It's null!", someObject);
, чи відключається це твердження у відправних бітах?
adb shell setprop debug.assert 1
в Eclipse?
su
, тоді setprop debug.assert 1
. Зверніть увагу, що код, який ви показуєте в розібраному вигляді, залишатиметься у складі випуску ( stackoverflow.com/a/5590378/506073 ). Я не вірю, що компілятору javac можна сказати не видавати тверджень, тому їх потрібно якось видалити. Просте рішення - обернути ключове слово assert у власну функцію, яку proguard може вам позбавити.
Коли твердження ввімкнені, 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 на практиці" пропонується використовувати:
$adb shell setprop dalvik.vm.enableassertions all
якщо ці налаштування не зберігаються на вашому телефоні, ви можете створити файл /data/local.prop із такими властивостями, як:
dalvik.vm.enableassertions=all
chmod 644
).
Це, на біс, мене викрикувало, що мої твердження не працювали, поки я не перевірив проблему в google ... Я відмовився від простих тверджень і піду з методами твердження junits.
Для зручності я використовую:
імпортувати статичний junit.framework.Assert. *;
Через статичний імпорт я згодом можу написати:
assertTrue (...); замість Assert.assertTrue (...);
Якщо ви стурбовані кодом доставки із твердженнями JUnit (або будь-яким іншим шляхом до класу), ви можете скористатися параметром конфігурації ProGuard 'pretumenosideeffects', який видалить шлях до класу, припускаючи, що його видалення нічого не робить для коду .
Напр.
-assumenosideeffects junit.framework.Assert {
*;
}
У мене є загальна бібліотека налагодження, в яку я вкладаю всі свої методи тестування, а потім використовую цю опцію, щоб видалити її з моїх випущених програм.
Це також усуває важко помітну проблему рядків, якими маніпулюють, які ніколи не використовуються в коді випуску. Наприклад, якщо ви пишете метод журналу налагодження, і в цьому методі ви перевіряєте режим налагодження перед реєстрацією рядка, ви все ще будуєте рядок, виділяєте пам'ять, викликаєте метод, але потім вибираєте нічого не робити. Видалення класу потім повністю видаляє виклики, тобто, поки ваш рядок побудований всередині виклику методу, він також зникає.
Переконайтеся, що по-справжньому безпечно просто зачищати рядки, проте це робиться без перевірки з боку ProGuard. Видалення будь-якого методу повернення порожнечі буде добре, однак, якщо ви берете будь-які повернені значення з того, що ви видаляєте, переконайтеся, що не використовуєте їх для фактичної операційної логіки.
-assumenosideeffects class junit.framework.Assert { *; }
Ви можете використовувати твердження, але для їх надійного використання потрібна певна робота. Властивість системи debug.assert
ненадійна; див. випуски 175697 , 65183 , 36786 та 17324 .
Одним із методів є переклад кожного assert
висловлювання на те, з чим може впоратися будь-яка програма виконання. Зробіть це за допомогою препроцесора джерела перед компілятором Java. Для прикладу візьмемо таке твердження:
assert x == 0: "Failure message";
Для побудови налагодження ваш препроцесор перекладе вищезазначене if
твердження:
{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }
Для виробничої збірки до порожнього виписки:
;
Зверніть увагу, що це контролюватиме твердження під час побудови, на відміну від часу виконання (звичайна практика).
Я не міг знайти готовий препроцесор, тому написав його . Див. Частину, що стосується тверджень. Ліцензія на копіювання тут .
Щоб додати відповідь Zulaxia на видалення Junit - Proguard вже є частиною Android SDK / Eclipse, і на наступній сторінці ви дізнаєтесь, як його увімкнути.
http://developer.android.com/guide/developing/tools/proguard.html
Також вищезазначене не працюватиме з останньою конфігурацією proguard за замовчуванням, оскільки воно використовує прапорець -dontoptimize, який потрібно вийняти та ввімкнути деякі оптимізації.
Використовуйте стандартне ключове слово Java assert , наприклад:
assert a==b;
Щоб це працювало, потрібно додати один рядок до /system/build.prop і перезавантажити телефон:
debug.assert=1
Це буде працювати на кореневому телефоні. Використовуйте якийсь файловий менеджер, здатний редагувати build.prop (наприклад, X-plore).
Плюси: більшість (усіх?) Телефонів Android постачаються з відключеними твердженнями. Навіть якщо ваш код випадково встановить значення false, додаток не перериватиметься та не працюватиме. Однак на вашому пристрої розробки ви отримаєте твердження про виняток.