Can I use assert on Android devices?

AndroidAssert

Android Problem Overview


I want to use the Assert keyword in my android apps to destroy my app in some cases on the emulator, or my device during testing. Is this possible?

It seems that the emulator just ignores my asserts.

Android Solutions


Solution 1 - Android

See the Embedded VM Control document (raw HTML from the source tree, or a nicely formatted copy).

Basically, the Dalvik VM is set to ignore assertion checks by default, even though the .dex byte code includes the code to perform the check. Checking assertions is turned on in one of two ways:

(1) by setting the system property "debug.assert" via:

adb shell setprop debug.assert 1

which I verified works as intended as long as you reinstall your app after doing this, or

(2) by sending the command line argument "--enable-assert" to the dalvik VM which might not be something app developers are likely to be able to do (somebody correct me if I'm wrong here).

Basically, there is a flag that can be set either globally, at a package level, or at a class level which enables assertions at that respective level. The flag is off by default, as a result of which the assertion checks are skipped.

I wrote the following code in my sample 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;
}
}

For this code, the dalvik byte code that is generated is (for 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


Notice how the static constructor invokes the method desiredAssertionStatus on the Class object and sets the class-wide variable $assertionsDisabled; also notice that in onCreate(), all of the code to throw java.lang.AssertionError is compiled in, but its execution is contingent upon the value of $assertionsDisabled which is set for the Class object in the static constructor.

It appears that JUnit's Assert class is what is used predominantly, so it is likely a safe bet to use that. The flexibility of the assert keyword is the ability to turn on assertions at development time and turn them off for shipping bits and instead fail gracefully.

Hope this helps.

Solution 2 - Android

When assertions are enabled, the assert keyword simply throws an AssertionError when the boolean expression is false.

So IMO, the best alternative, esp. if you're averse to depend on junit, is to throw an AssertionError explicitly as shown below:

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

An alternative to the above statement is:

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

Where the method is defined as:

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

The Oracle java docs recommend throwing an AssertionError as an acceptable alternative.

I guess you can configure Proguard to strip out these calls for production code.

Solution 3 - Android

In "Android in Practice" it is suggested to use:

$adb shell setprop dalvik.vm.enableassertions all

if this settings is not persisted on your phone then you can create /data/local.prop file with properties like:

dalvik.vm.enableassertions=all

Solution 4 - Android

It was bugging the hell out of me, that my assertions didnt work, until I checked the issue out on google... I gave up on simple assertions and will go with junits assertion methods.

For convenience purposes I am using:

import static junit.framework.Assert.*;

Due to the static import I can later write:

assertTrue(...); instead of Assert.assertTrue(...);

Solution 5 - Android

If you're concerned about shipping code with the JUnit asserts in (or any other class path), you can use the ProGuard config option 'assumenosideeffects', which will strip out a class path on the assumption that removing it does nothing to the code.

Eg.

-assumenosideeffects junit.framework.Assert {
*;
}

I have a common debug library I put all my testing methods in, and then use this option to strip it from my released apps.

This also removes the hard to spot problem of strings being manipulated that are never used in release code. For example if you write a debug log method, and in that method you check for debug mode before logging the string, you are still constructing the string, allocating memory, calling the method, but then opting to do nothing. Stripping the class out then removes the calls entirely, meaning as long as your string is constructed inside the method call, it goes away as well.

Make sure it is genuinely safe to just strip the lines out however, as it is done with no checking on ProGuard's part. Removing any void returning method will be fine, however if you are taking any return values from whatever you are removing, make sure you aren't using them for actual operational logic.

Solution 6 - Android

You can use assertions, but it takes some work to use them reliably. System property debug.assert is unreliable; see issues 175697, 65183, 36786 and 17324.

One method is to translate each assert statement to something any runtime can deal with. Do this with a source preprocessor in front of the Java compiler. For example, take this statement:

assert x == 0: "Failure message";

For a debug build, your preprocessor would translate the above to an if statement:

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

For a production build, to an empty statement:

;

Note that this would control assertions at build time, as opposed to run time (the usual practice).

I could find no ready-made preprocessor, so I scripted one. See the part dealing with assertions. Licence to copy is here.

Solution 7 - Android

To add to Zulaxia's answer on stripping out Junit - Proguard is already part of Android SDK /Eclipse and the following page tells you how to enable it.

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

Also the above wont work with the latest default proguard configuration because it uses the -dontoptimize flag which must be taken out and some of the optimizations turned on.

Solution 8 - Android

Use standard Java assert keyword, for example:

assert a==b;

For this to work, you have to add one line to /system/build.prop, and reboot phone:

debug.assert=1

This would work on rooted phone. Use some file manager capable to edit build.prop (e.g. X-plore).

Pluses: most (all?) Android phones ship with assertions disabled. Even if your code accidentally asserts to false, app won't interrupt or crash. However, on your development device you'll get assertion exception.

Solution 9 - Android

The API provides the JUnit Assert.

You can do

import static junit.framework.Assert.*;

now you can use all the functions like assertTrue, assertEquals, assertNull that are provided in the junit framework.

Be careful not to import the Junit4 framework through eclipse, that would be the org.junit package. You have to use the junit.framework package to get it working on an android device or the emulator.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJanuszView Question on Stackoverflow
Solution 1 - AndroidscorpiodawgView Answer on Stackoverflow
Solution 2 - AndroidDheeraj VepakommaView Answer on Stackoverflow
Solution 3 - AndroidmarcinjView Answer on Stackoverflow
Solution 4 - AndroidReady4AndroidView Answer on Stackoverflow
Solution 5 - AndroidZulaxiaView Answer on Stackoverflow
Solution 6 - AndroidMichael AllanView Answer on Stackoverflow
Solution 7 - AndroidSean MooreView Answer on Stackoverflow
Solution 8 - AndroidPointer NullView Answer on Stackoverflow
Solution 9 - AndroidJRLView Answer on Stackoverflow