我可以在Android设备上使用assert吗?
我想在我的android应用程序中使用Assert关键字在testing过程中在模拟器上或者我的设备上销毁我的应用程序。 这可能吗?
仿真器似乎忽略了我的断言。
该API提供了JUnit Assert 。
你可以做
import static junit.framework.Assert.*;
现在你可以使用所有在junit框架中提供的assertTrue,assertEquals,assertNull等函数。
注意不要通过eclipse导入Junit4框架,这将是org.junit包。 你必须使用junit.framework包来使它在android设备或模拟器上工作。
请参阅Embedded VM Control文档( 源树中的原始HTML或格式良好的副本)。
基本上,Dalvik虚拟机默认设置为忽略断言检查,即使.dex字节代码包含执行检查的代码。 检查断言的方式有两种:
(1)通过设置系统属性“debug.assert”:
adb shell setprop debug.assert 1
我已经validation过,只要你重新安装你的应用程序后,这样做,或
(2)通过发送命令行参数“–enable-assert”给dalvik虚拟机,这可能不是应用程序开发人员可能做的事情(有人纠正我,如果我在这里错了)。
基本上,可以在全球范围内,在一揽子层面上或者在能够在各个层次上进行断言的课程层面上设置一个标志。 该标志默认是closures的,因此断言检查被跳过。
我在示例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
// 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 //方法@ 0001
000372:1501 037f | 0003:const / high16 v1,#int 2130903040 //#7f03
000560: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:投掷v1
000398:0e00 | 0016:return-void
注意静态构造函数如何在Class对象上调用desiredAssertionStatus方法,并设置类的variables$ assertionsDisabled; 还要注意,在onCreate()中,所有抛出java.lang.AssertionError的代码都被编译进去,但是它的执行取决于在静态构造函数中为Class对象设置的$ assertionsDisabled的值。
看来JUnit的Assert类是主要使用的,所以使用它可能是一个安全的select。 assert关键字的灵活性在于能够在开发时打开断言,并closures它们以传送位,而不是优雅地失败。
希望这可以帮助。
当断言被启用时,当布尔expression式为false
时, assert
关键字只会引发一个AssertionError
。
所以IMO是最好的select, 如果你不愿意依赖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文档build议抛出一个AssertionError
作为可接受的select。
我想你可以configurationProguard去掉这些调用生产代码。
在“Android实践”中,build议使用:
$adb shell setprop dalvik.vm.enableassertions all
如果这个设置没有保存在你的手机上,那么你可以使用如下属性创build/data/local.prop文件:
dalvik.vm.enableassertions=all
这是在窃听我的地狱,我的断言没有奏效,直到我在谷歌上检查了这个问题…我放弃了简单的断言,并将与junit断言方法。
为了方便起见,我正在使用:
import static junit.framework.Assert。*;
由于静态导入我可以稍后写:
assertTrue(…); 而不是Assert.assertTrue(…);
如果您担心JUnit在(或任何其他类path)中声明的运行代码,那么可以使用ProGuardconfiguration选项“assumenosideeffects”,它将删除类path,假定删除它对代码没有任何影响。
例如。
-assumenosideeffects junit.framework.Assert { *; }
我有一个通用的debugging库,我把我所有的testing方法,然后使用这个选项从我发布的应用程序中删除。
这也消除了在发布代码中从未使用过的string难以发现的问题。 例如,如果您编写debugging日志方法,并且在该方法中,在loggingstring之前检查debugging模式,则仍在构造string,分配内存,调用方法,但是不select任何操作。 剥离类然后完全删除调用,这意味着只要您的string是在方法调用内部构造的,它也会消失。
确保它是真正安全的,只是将线条剥离,而不需要检查ProGuard的部分。 删除任何无效的返回方法都可以,但是如果你从任何你正在删除的任何返回值,确保你没有使用它们的实际操作逻辑。
为了增加Zulaxia关于删除Junit的答案 – Proguard已经是Android SDK / Eclipse的一部分,接下来的页面会告诉你如何启用它。
http://developer.android.com/guide/developing/tools/proguard.html
此外,上述不会使用最新的默认proguardconfiguration,因为它使用-dontoptimize标志,必须取出和一些优化打开。
你可以使用断言,但需要一些工作来可靠地使用它们。 系统属性debug.assert
不可靠。 参见问题175697,65183,36786和17324 。
要在Android上使断言可靠,您必须将每个assert
语句翻译为所有运行时可以处理的内容。 这可以通过Java编译器前面的源预处理器完成。 例如,考虑这个说法:
assert x == 0: "Failure message";
在debugging版本中,预处理器会将其转换为if
语句:
{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }
在生产版本中,对一个空的陈述:
;
请注意,这样的断言必须由源预处理器在构build时启用或禁用,而不是由虚拟机在运行时启用或禁用。 这与传统的Java实践不同。
我找不到一个现成的预处理器,所以我必须编写自己的脚本(请参阅处理断言的部分)。 这里复制许可证。
使用标准的Java 断言关键字,例如:
assert a==b;
为此,您必须将一行添加到/system/build.prop,然后重新启动电话:
debug.assert=1
这将在根植电话上工作。 使用一些能够编辑build.prop的文件pipe理器(例如X-plore)。
加号:绝大多数(所有?)Android手机都附带断言。 即使您的代码意外地被断言,应用程序也不会中断或崩溃。 但是,在你的开发设备上,你会得到断言exception。