Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

better way to do Debug only assert code

Tags:

android

I am writing my first Android application and I am liberally using asserts() from junit.framework.Assert

I would like to find a way to ensure that the asserts are only compiled into the debug build, not in the release build.

I know how to query the android:debuggable attribute from the manifest so I could create a variable and accomplish this in the following fashon:

static final boolean mDebug = ...

if (mDebug) Assert.assertNotNull(view);

Is there a better way to do this? i.e. I would prefer not to use an if() with each assert.

thanks

like image 747
jbww Avatar asked Feb 18 '11 16:02

jbww


People also ask

Is assert only for debugging?

Assert works only in DEBUG mode - or, at least, when the DEBUG variable is defined. Otherwise, all those checks will simply get removed from the build result, so they will not impact your application when running in RELEASE mode.

What is debug assert?

Debug. Assert(Boolean) with only one argument, the Assert method checks the condition and, if the result is false, outputs the contents of the call stack to the Output window. The following example shows System. Diagnostics. Trace.

Should assert be used in production code?

JUnit assertions are intended to be used in test code, but not in production code.

Should you use assert in Python?

Assert should only be used for testing and debugging — not in production environments. Because assert statements only run when the __debug__ variable is set to True , a Python interpreter can disable them.


3 Answers

I think the Java language's assert keyword is likely what you want. Under the covers, the assert keyword essentially compiles into Dalvik byte code that does two things:

  1. Checks whether the static variable assertionsDisabled (set in the class' static constructor via a call to java.lang.Class.desiredAssertionStatus()) is != 0 and if so, does nothing
  2. If it is 0, then it checks the assertion expression and throws a java.lang.AssertionError if the expression resolves to false, effectively terminating your application.

The Dalvik runtime by default has assertions turned off, and therefore desiredAssertionStatus always returns 1 (or more precisely, some non-zero value). This is akin to running in "retail" mode. In order to turn on "debug" mode, you can run the following command against the emulator or the device:

adb shell setprop debug.assert 1

and this should do the trick (should work on the emulator or any rooted debugging-ready device).

Note however that the aforementioned Dalvik code that checks the value of assertionsDisabled and throws an AssertionError if the expression is false is always included in your byte code and liberal sprinkling of asserts in your code may lead to byte code bloat.

Please see this for a bit more detail: Can I use assert on Android devices?

like image 102
scorpiodawg Avatar answered Oct 24 '22 01:10

scorpiodawg


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 class 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.

like image 21
Zulaxia Avatar answered Oct 24 '22 00:10

Zulaxia


I mean if you were using a language feature, like assert(), the compiler should be able to strip that out. But this is an actual class and if a class is referenced by executable code it will be included or assumed included in the final product by the compiler.

However there is nothing stopping you from creating a script that removes all the references to the Assert class in all of your code base before compilation.

Another approach would be to make a test project that targets your application and within JUnit tests actually calls the Assert on the areas which you want to make sure work. I personally like this approach because it is a nice and clean separation of test and application.

If you are just worried about the having an if-statement everywhere, then just wrap Assert with your own class, DebuggableAssert which does that check before each call to Assert.X. It will be sort of less performant because of the method entry/exit and the conditionals but if you can maintain your code better then it might be worth it.

like image 43
Greg Giacovelli Avatar answered Oct 24 '22 01:10

Greg Giacovelli