Android 장치에서 assert를 사용할 수 있습니까?


88

내 Android 앱에서 Assert 키워드 를 사용하여 경우에 따라 에뮬레이터 또는 테스트 중에 내 장치에서 내 앱을 파괴하고 싶습니다. 이것이 가능한가?

에뮬레이터가 내 주장을 무시하는 것 같습니다.


2
Dalvik이 아닌 ART의 경우 stackoverflow.com/questions/35997703/…을
fadden

1
허용되는 답변은 오해의 소지가 있습니다.
감소 활동

답변:


-7

API는 JUnit Assert를 제공합니다 .

넌 할 수있어

import static junit.framework.Assert.*;

이제 junit 프레임 워크에서 제공되는 assertTrue, assertEquals, assertNull과 같은 모든 함수를 사용할 수 있습니다.

org.junit 패키지 인 eclipse를 통해 Junit4 프레임 워크를 가져 오지 않도록주의하십시오. 안드로이드 장치 또는 에뮬레이터에서 작동하려면 junit.framework 패키지를 사용해야합니다.


51
OP는 junit.framework.Assert와 달리 JIT에 의해 최적화 될 수있는 "assert 키워드"를 요청했습니다. 바로 이런 이유로 저는 여기에 왔습니다. 다른 답변 중 일부가 더 도움이되기를 바랍니다.
Martin

27
나는 무례한 것이 싫지만 이것은 질문에 대한 답변이 아니기 때문에 받아 들여진 대답이되어서는 안됩니다 (@Martin의 의견에 동의합니다). 다른 답변은 assert 키워드 기능을 올바르게 만드는 방법을 설명합니다. 예를 들어 "adb shell setprop debug.assert 1"실행
jfritz42

3
OP가 assert 키워드에 대해 질문했기 때문에 비추천했습니다. @scorpiodawg는 아래에 프로세스를 설명했습니다. stackoverflow.com/a/5563637/484261

scorpiodawg의 답변은 1 년 후에 나왔기 때문에 OP가 어떤 이유로 답변을 수락 된 것으로 표시해야한다고 느꼈기 때문에이 답변이 수락 된 것 같습니다. 이 태도는 너무 불완전하거나 완전히 끔찍한 답변을 많이 만듭니다.
async

145

Embedded VM Control 문서 ( 소스 트리의 원시 HTML 또는 멋진 형식의 사본)를 참조하십시오.

기본적으로 Dalvik VM은 .dex 바이트 코드에 검사를 수행하는 코드가 포함되어 있더라도 기본적으로 어설 션 검사를 무시하도록 설정됩니다. 어설 션 확인은 다음 두 가지 방법 중 하나로 설정됩니다.

(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 키워드의 유연성은 개발 시간에 assertion을 켜고 비트 전달을 위해 끄고 대신 정상적으로 실패하는 기능입니다.

도움이 되었기를 바랍니다.


Google이 검색 가능한 소스를 제거한 것으로 보입니다 (여기에 다른 질문에 대한 답변에서 이에 대한 참조를 보았습니다). 가장 좋은 방법은 소스를 얻거나 검색 엔진에서이를 찾아 보는 것입니다. "dalvik / embedded-vm-control.html"을 검색합니다. 여기에 한 곳이 있습니다 : assembla.com/code/android-gb-for-sharp-is01/git/nodes/dalvik/… . 도움이 되었기를 바랍니다.
scorpiodawg 2011

매우 유용합니다. 감사합니다. 그래도 마지막에서 두 번째 단락의 구분에 혼란 스럽습니다. 우리는 두 종류의 assert에 대해 논의하고 있습니다 : 첫 번째는 assertNotNull ()과 같은 JUnit Assert 패키지의 메소드이고 두 번째는 자바 언어 'assert'키워드입니다. 귀하의 답변은 둘 다에 적용됩니까? 예를 들어, 나와 import static junit.framework.Assert.*같은 방법 중 하나를 사용 assertNotNull("It's null!", someObject);하면이 어설 션이 배송 비트에서 해제됩니까?
Jeffro 2011

1
안녕하세요 Jeffro, 저는 그렇게 믿지 않습니다. junit.framework.Assert는 입력 조건이 거짓 인 것으로 판명 될 때 예외를 발생시키는 클래스입니다. 반면 assert 키워드는 언어에 내장되어 있습니다. 도움이 되었기를 바랍니다.
scorpiodawg 2011

3
adb shell setprop debug.assert 1Eclipse에서 할 수있는 방법이 있습니까?
Pacerier

1
루트 인 경우 장치에서 실행되는 터미널에서 어설 션을 수행 할 수도 있습니다. 먼저 su, 다음 setprop debug.assert 1. 디스 어셈블 된 것으로 표시된 코드는 릴리스 빌드 ( stackoverflow.com/a/5590378/506073 )에 유지됩니다. 나는 javac 컴파일러가 어설 션을 내 보내지 말라고 말할 수 있다고 생각하지 않으므로 어떻게 든 제거해야합니다. 이에 대한 간단한 해결책은 proguard가 제거 할 수있는 자체 함수에서 assert 키워드를 래핑하는 것입니다.
ahcox 2012

10

어설 션이 활성화되면 assertAssertionError 되면 부울 표현식이 키워드는 단순히를 throw합니다 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).
Paulo

5

내가 Google에서 문제를 확인할 때까지 내 주장이 작동하지 않았다는 것은 지옥을 괴롭 히고 있었다. 나는 단순한 주장을 포기하고 junits 주장 방법으로 갈 것이다.

편의를 위해 다음을 사용합니다.

import static junit.framework.Assert. *;

정적 가져 오기로 인해 나중에 다음과 같이 작성할 수 있습니다.

assertTrue (...); 대신 Assert.assertTrue (...);


4

JUnit 어설 션 (또는 다른 클래스 경로)을 사용하여 코드를 전달하는 것이 염려되는 경우 ProGuard 구성 옵션 'assumenosideeffects'를 사용하여 제거하면 코드에 아무런 영향이 없다는 가정하에 클래스 경로를 제거 할 수 있습니다. .

예 :

-assumenosideeffects junit.framework.Assert {
*;
}

모든 테스트 방법을 넣은 공통 디버그 라이브러리가 있으며이 옵션을 사용하여 출시 된 앱에서 제거합니다.

이것은 또한 릴리스 코드에서 사용되지 않는 조작되는 문자열의 발견하기 어려운 문제를 제거합니다. 예를 들어 디버그 로그 메서드를 작성하고 해당 메서드에서 문자열을 로깅하기 전에 디버그 모드를 확인하는 경우 여전히 문자열을 구성하고 메모리를 할당하고 메서드를 호출 한 다음 아무 작업도 수행하지 않습니다. 그런 다음 클래스를 제거하면 호출이 완전히 제거됩니다. 즉, 메서드 호출 내부에서 문자열이 생성되는 한 해당 문자열도 사라집니다.

그러나 ProGuard의 부분을 확인하지 않고 수행되므로 선을 제거하는 것이 진정으로 안전한지 확인하십시오. 무효 반환 방법을 제거하는 것은 괜찮습니다. 그러나 제거하는 항목에서 반환 값을 가져 오는 경우 실제 작동 논리에 사용하지 않는지 확인하십시오.


1
적절한 구문은 다음과 같습니다.-assumenosideeffects class junit.framework.Assert { *; }
Pooks

혼란스러운 대답. 언급 된 명령으로 인해 proguard 오류가 발생합니다. Pooks에서 수정 한 명령은 여전히 ​​이진 dex 파일에서 어설 션을 제거하지 않습니다.
포인터 Null

@PointerNull 같은 문제가 있습니다. 제거되지 않을 것이라고 주장합니다.
Mahdi

3

어설 션을 사용할 수 있지만 안정적으로 사용하려면 약간의 작업이 필요합니다. 시스템 속성debug.assert 이 신뢰할 수 없습니다. 문제 175697 , 65183 , 3678617324 참조 .

한 가지 방법은 각 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 플래그를 사용하고 일부 최적화를 설정하기 때문에 최신 기본 proguard 구성에서는 작동하지 않습니다.


0

다음과 같은 표준 Java assert 키워드를 사용하십시오 .

assert a==b;

이 작업을 수행하려면 /system/build.prop에 한 줄을 추가하고 전화를 재부팅해야합니다.

debug.assert=1

이것은 루팅 된 전화에서 작동합니다. build.prop (예 : X-plore)을 편집 할 수있는 파일 관리자를 사용합니다.

장점 : 대부분의 (모두?) Android 휴대폰은 어설 션이 비활성화 된 상태로 제공됩니다. 코드가 실수로 거짓으로 주장하더라도 앱이 중단되거나 충돌하지 않습니다. 그러나 개발 장치에서는 어설 션 예외가 발생합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.