Chcę użyć słowa kluczowego Assert w moich aplikacjach na Androida, aby w niektórych przypadkach zniszczyć moją aplikację na emulatorze lub na moim urządzeniu podczas testowania. czy to możliwe?
Wygląda na to, że emulator po prostu ignoruje moje zapewnienia.
Odpowiedzi:
Interfejs API zapewnia JUnit Assert .
Możesz to zrobić
import static junit.framework.Assert.*;
teraz możesz używać wszystkich funkcji, takich jak assertTrue, assertEquals, assertNull, które są udostępniane w ramach junit.
Uważaj, aby nie importować frameworka Junit4 przez eclipse, to byłby pakiet org.junit. Musisz użyć pakietu junit.framework, aby działał na urządzeniu z systemem Android lub w emulatorze.
źródło
Zobacz dokument Embedded VM Control (surowy kod HTML z drzewa źródłowego lub ładnie sformatowana kopia).
Zasadniczo maszyna wirtualna Dalvik jest ustawiona tak, aby domyślnie ignorować sprawdzanie potwierdzenia, nawet jeśli kod bajtowy .dex zawiera kod do wykonania sprawdzenia. Sprawdzanie potwierdzeń jest włączane na jeden z dwóch sposobów:
(1) ustawiając właściwość systemową „debug.assert” przez:
adb shell setprop debug.assert 1
co sprawdziłem, działa zgodnie z przeznaczeniem, o ile po wykonaniu tej czynności ponownie zainstalujesz aplikację lub
(2) wysyłając argument wiersza poleceń „--enable-assert” do maszyny wirtualnej dalvik, co może nie być czymś, co twórcy aplikacji prawdopodobnie nie będą w stanie zrobić (ktoś poprawi mnie, jeśli się mylę).
Zasadniczo istnieje flaga, którą można ustawić globalnie, na poziomie pakietu lub na poziomie klasy, co umożliwia asercje na tym odpowiednim poziomie. Flaga jest domyślnie wyłączona, w wyniku czego kontrole potwierdzeń są pomijane.
Napisałem następujący kod w mojej przykładowej aktywności:
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; } }
Dla tego kodu generowany kod bajtowy dalvik (dla systemu 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
Zwróć uwagę, jak konstruktor statyczny wywołuje metodę pożądanąAssertionStatus w obiekcie Class i ustawia zmienną dla całej klasy $ assertionsDisabled; Zauważ również, że w onCreate () cały kod do zgłaszania java.lang.AssertionError jest wkompilowany, ale jego wykonanie jest zależne od wartości $ assertionsDisabled, która jest ustawiona dla obiektu Class w konstruktorze statycznym.
Wygląda na to, że klasa Assert JUnit jest tym, co jest używane przeważnie, więc prawdopodobnie jest to bezpieczne. Elastyczność słowa kluczowego assert polega na możliwości włączania asercji w czasie programowania i wyłączania ich w celu wysyłania bitów, a zamiast tego bezproblemowo zawodzą.
Mam nadzieję że to pomoże.
źródło
import static junit.framework.Assert.*
i następnie użyję jednej z jego metod, na przykładassertNotNull("It's null!", someObject);
, czy to potwierdzenie jest wyłączone w bitach wysyłkowych?adb shell setprop debug.assert 1
w Eclipse?su
, następniesetprop debug.assert 1
. Zwróć uwagę, że kod, który pokazujesz zdemontowany, pozostanie w kompilacji wydania ( stackoverflow.com/a/5590378/506073 ). Nie wierzę, że kompilatorowi javac można powiedzieć, aby nie emitował asercji, więc należy je jakoś usunąć. Prostym rozwiązaniem jest umieszczenie słowa kluczowego assert we własnej funkcji, którą program Proguard może dla Ciebie usunąć.Gdy asercje są włączone,
assert
słowo kluczowe po prostu zgłasza,AssertionError
gdy wyrażenie boolowskie jestfalse
.Zatem IMO, najlepsza alternatywa, zwł. jeśli nie chcesz polegać na junicie, rzuć
AssertionError
jawnie, jak pokazano poniżej:assert x == 0 : "x = " + x;
Alternatywą dla powyższego stwierdzenia jest:
Utils._assert(x == 0, "x = " + x);
Gdzie metoda jest zdefiniowana jako:
public static void _assert(boolean condition, String message) { if (!condition) { throw new AssertionError(message); } }
Dokumentacja java Oracle zaleca zgłoszenie
AssertionError
jako akceptowalnej alternatywy.Wydaje mi się, że możesz skonfigurować Proguard, aby wyeliminować te wywołania kodu produkcyjnego.
źródło
W „Android w praktyce” sugeruje się użycie:
$adb shell setprop dalvik.vm.enableassertions all
jeśli te ustawienia nie są utrwalone w telefonie, możesz utworzyć plik /data/local.prop z właściwościami takimi jak:
dalvik.vm.enableassertions=all
źródło
chmod 644
).Diabelnie mnie to denerwowało, że moje twierdzenia nie zadziałały, dopóki nie sprawdziłem problemu w google ... Zrezygnowałem z prostych twierdzeń i pójdę z metodami asercji junits.
Dla wygody używam:
import static junit.framework.Assert. *;
Ze względu na import statyczny mogę później napisać:
assertTrue (...); zamiast Assert.assertTrue (...);
źródło
Jeśli obawiasz się wysyłania kodu z potwierdzeniami JUnit w (lub dowolnej innej ścieżce klas), możesz użyć opcji konfiguracyjnej ProGuard „assumenosideeffects”, która usunie ścieżkę klasy przy założeniu, że usunięcie go nic nie zmienia z kodem .
Na przykład.
Mam wspólną bibliotekę debugowania, w której umieszczam wszystkie moje metody testowania, a następnie używam tej opcji, aby usunąć ją z moich wydanych aplikacji.
Eliminuje to również trudny do zauważenia problem manipulowania napisami, które nigdy nie są używane w kodzie wydania. Na przykład, jeśli napiszesz metodę dziennika debugowania i w tej metodzie sprawdzisz tryb debugowania przed zarejestrowaniem ciągu, nadal konstruujesz ciąg, alokujesz pamięć, wywołujesz metodę, ale potem nie robisz nic. Usunięcie klasy, a następnie całkowicie usuwa wywołania, co oznacza, że tak długo, jak łańcuch jest zbudowany wewnątrz wywołania metody, również znika.
Upewnij się jednak, że po prostu usunięcie linek jest naprawdę bezpieczne, ponieważ odbywa się to bez sprawdzania części ProGuard. Usunięcie metody zwracającej void będzie w porządku, jednak jeśli pobierasz jakiekolwiek wartości zwracane z tego, co usuwasz, upewnij się, że nie używasz ich do rzeczywistej logiki operacyjnej.
źródło
-assumenosideeffects class junit.framework.Assert { *; }
Możesz używać asercji, ale ich niezawodne użycie wymaga trochę pracy. Właściwość systemu
debug.assert
jest zawodna; patrz numery 175697 , 65183 , 36786 i 17324 .Jedną z metod jest przetłumaczenie każdej
assert
instrukcji na coś, z czym może sobie poradzić każde środowisko wykonawcze. Zrób to z preprocesorem źródła przed kompilatorem Java. Weźmy na przykład to stwierdzenie:assert x == 0: "Failure message";
W przypadku kompilacji do debugowania preprocesor przetłumaczy powyższe na
if
instrukcję:{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }
W przypadku kompilacji produkcyjnej do pustej instrukcji:
;
Zauważ, że kontrolowałoby to asercje w czasie kompilacji, a nie w czasie wykonywania (zwykła praktyka).
Nie mogłem znaleźć gotowego preprocesora, więc napisałem jeden z nich . Zobacz część dotyczącą twierdzeń. Licencja na kopiowanie jest tutaj .
źródło
Aby dodać do odpowiedzi Zulaxii na temat usuwania Junit - Proguard jest już częścią Android SDK / Eclipse, a na następnej stronie opisano, jak go włączyć.
http://developer.android.com/guide/developing/tools/proguard.html
Powyższe również nie będzie działać z najnowszą domyślną konfiguracją proguard, ponieważ używa flagi -dontoptimize, którą należy usunąć i włączyć niektóre optymalizacje.
źródło
Użyj standardowego słowa kluczowego assert Java , na przykład:
assert a==b;
Aby to zadziałało, musisz dodać jedną linię do /system/build.prop i zrestartować telefon:
debug.assert=1
To zadziała na zrootowanym telefonie. Użyj jakiegoś menedżera plików, który może edytować build.prop (np. X-plore).
Plusy: większość (wszystkich?) Telefonów z Androidem jest dostarczanych z wyłączonymi asercjami. Nawet jeśli Twój kod przypadkowo potwierdzi fałsz, aplikacja nie przerywa pracy ani nie ulega awarii. Jednak na swoim urządzeniu programistycznym otrzymasz wyjątek asercji.
źródło