更好的方法只调试断言代码

时间:2011-02-18 16:12:55

标签: android

我正在编写我的第一个Android应用程序,我很自由地使用junit.framework.Assert

中的asserts()

我想找到一种方法来确保断言只被编译到调试版本中,而不是发布版本中。

我知道如何从清单中查询android:debuggable属性,所以我可以创建一个变量并在以下时间完成:

static final boolean mDebug = ...

if(mDebug)     Assert.assertNotNull(视图);

有更好的方法吗?即我不想在每个断言中使用if()。

感谢

3 个答案:

答案 0 :(得分:19)

我认为Java语言的assert关键字可能就是你想要的。在幕后,assert关键字基本上编译成Dalvik字节代码,它执行两项操作:

  1. 检查静态变量assertionsDisabled(通过调用java.lang.Class.desiredAssertionStatus()在类'静态构造函数中设置)是否为!= 0,如果是,则不执行任何操作
  2. 如果 0,那么它会检查断言表达式并在表达式解析为java.lang.AssertionError时抛出false,从而有效地终止您的应用程序。
  3. 默认情况下,Dalvik运行时关闭断言,因此desiredAssertionStatus始终返回1(或更确切地说,某些非零值)。这类似于以“零售”模式运行。要打开“调试”模式,可以对仿真器或设备运行以下命令:

    adb shell setprop debug.assert 1
    

    这应该可以解决问题(应该在仿真器或任何有根调试的设备上工作)。

    但请注意,如果表达式为false,前面提到的检查assertionsDisabled的值并抛出AssertionError的Dalvik代码总是包含在您的字节代码中,并自由地汇集assert个在您的代码中可能会导致字节代码膨胀。

    请参阅此处了解更多详情:Can I use assert on Android devices?

答案 1 :(得分:8)

如果您担心在(或任何其他类路径)中使用JUnit断言传送代码,您可以使用ProGuard配置选项'assumenosideeffects',这将删除类路径,假设删除它什么都不做代码。

EG。

-assumenosideeffects class junit.framework.Assert {
*;
}

我有一个通用的调试库,我将所有测试方法都放入其中,然后使用此选项从我发布的应用程序中删除它。

这也消除了从未在发布代码中使用过的操作字符串的难以发现的问题。例如,如果您编写调试日志方法,并且在该方法中,在记录字符串之前检查调试模式,您仍在构造字符串,分配内存,调用方法,但随后选择不执行任何操作。剥离类然后完全删除调用,这意味着只要你的字符串在方法调用中构造,它就会消失。

确保将线条剥离是绝对安全的,因为没有检查ProGuard的部分。删除任何返回的void方法都没问题,但是如果你要删除任何返回值,请确保你没有将它们用于实际的操作逻辑。

答案 2 :(得分:0)

我的意思是如果你使用语言功能,比如assert(),编译器应该能够将其去掉。但这是一个实际的类,如果一个类被可执行代码引用,它将被编译器包含或假设包含在最终产品中。

但是,在编译之前,没有什么能阻止您创建一个脚本来删除所有代码库中对Assert类的所有引用。

另一种方法是制作一个针对您的应用程序的测试项目,并且在JUnit测试中实际调用您希望确保工作的区域的Assert。我个人喜欢这种方法,因为它是一个很好的,干净的测试和应用程序分离。

如果你只是担心到处都有if语句,那么只需用自己的类包装Assert,DebuggableAssert在每次调用Assert.X之前进行检查。由于方法的进入/退出和条件限制,它的性能将会降低,但是如果你能更好地维护你的代码,那么它可能是值得的。