【问题标题】:AndroidTestCase assertActivityRequiresPermission() not asserting correctlyAndroidTestCase assertActivityRequiresPermission() 未正确断言
【发布时间】:2014-10-24 14:26:04
【问题描述】:

https://gist.github.com/blundell/ff2ac1d5ff0a41519c36 http://developer.android.com/reference/android/test/AndroidTestCase.html#assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String)

我已经为活动的安全权限编写了一个测试,但是它没有达到我的预期。

我在清单中声明我的活动需要许可。 我运行断言此权限的测试。

这是一个应该通过但没有通过的示例测试:

AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.blundell.myapplication">

  <application>
    <activity
      android:name=".SecondActivity"
      android:permission="perm.foo.bar" />
  </application>

</manifest>

我的测试用例:

package com.blundell.myapplication;

import android.app.Application;
import android.test.ApplicationTestCase;

/**
 * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
 */
public class ApplicationTest extends ApplicationTestCase<Application> {

    private static final String PACKAGE = "com.blundell.myapplication";

    public ApplicationTest() {
        super(Application.class);
    }

    public void testSecondActivityRequiresFooBarPermission() throws Exception {
        assertActivityRequiresPermission(PACKAGE, PACKAGE + ".SecondActivity", "perm.foo.bar");
    }
}

存根活动:

package com.blundell.myapplication;

import android.app.Activity;

public class SecondActivity extends Activity {
}

测试失败时的堆栈跟踪:

junit.framework.AssertionFailedError: expected security exception for perm.foo.bar
at android.test.AndroidTestCase.assertActivityRequiresPermission(AndroidTestCase.java:99)
at com.blundell.myapplication.ApplicationTest.testSecondActivityRequiresFooBarPermission(ApplicationTest.java:15)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701)

编辑:

我发现使用 gradle 无论如何您都可以将 AndroidManifest 添加到您的测试中,并且它将被合并: @Manish Mulimani 我添加了仪器标签,但这并没有使测试通过。 (添加一个 IntentFilter 就可以了)。

/src/androidTest/AndroidManifext.xml

   <instrumentation
    android:label="new label to prove tools:replace works"
    android:name="android.test.InstrumentationTestRunner"
    android:targetPackage="com.blundell.myapplication.test"
    tools:replace="targetPackage, label" />

【问题讨论】:

  • 在使用权限之前,您是否尝试过在清单文件中添加permission 元素?
  • 是的,没有区别 :-(
  • 我已经更新了我的答案。

标签: android testing assertions android-permissions


【解决方案1】:

测试应用和被测应用运行在同一个进程中。因此测试用例通过了,因为测试应用程序不需要请求权限来启动活动。

要测试权限,测试应用程序应该在不同的进程中运行。这可以通过将测试包名称分配给测试应用程序清单的instrumentation 元素中的android:targetPackage 来完成。

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.blundell.myapplication.test"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:debuggable="true">
        <uses-library android:name="android.test.runner" />
    </application>
    <instrumentation android:label="Tests for com.blundell.myapplication.test" android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.blundell.myapplication.test" android:handleProfiling="false" android:functionalTest="false" />
</manifest>

这里是旧android包com.android.globalsearchmanifest文件,使用方法相同。这是该清单文件中留下的注释:

我们是自我检测的,因此可以运行测试,但因为这是 对于权限测试,我们没有检测任何应用程序(我们希望 从外部访问它)。

注意:如果您使用的是gradle,那么您需要手动生成测试包,安装并测试它。原因来自docs

instrumentation 节点的 targetPackage 属性的值 在测试应用程序清单中自动填充 被测应用的包名,即使它是通过 defaultConfig 和/或 Build Type 对象。这是原因之一 清单是自动生成的。

我按照这些步骤手动构建和执行测试包。

  1. 在 app/build.gradle 中:将 applicationId 设置为“com.blundell.myapplication.test”
  2. 构建测试包:./gradlew assembleDebugTest
  3. 安装测试包:adb install -r ./app/build/outputs/apk/app-debug-test-unaligned.apk
  4. 运行测试:adb shell am instrument -w com.blundell.myapplication.test/android.test.InstrumentationTestRunner

这是 logcat 的输出:

10-28 21:06:46.749 32649 32662 I TestRunner: started: testActivityPermission(com.blundell.myapplication.ApplicationTest)
10-28 21:06:46.754   983   993 I ActivityManager: START u0 {flg=0x10000000 cmp=com.blundell.myapplication/.SecondActivity} from pid 32649
10-28 21:06:46.754   983   993 W ActivityManager: Permission Denial: starting Intent { flg=0x10000000 cmp=com.blundell.myapplication/.SecondActivity } from ProcessRecord{427f4f78 32649:com.blundell.myapplication.test/u0a10111} (pid=32649, uid=10111) requires perm.foo.bar
10-28 21:06:46.755 32649 32662 I TestRunner: finished: testActivityPermission(com.blundell.myapplication.ApplicationTest)
10-28 21:06:46.755 32649 32662 I TestRunner: passed: testActivityPermission(com.blundell.myapplication.ApplicationTest)

【讨论】:

  • 因此,对于 Gradle,我们需要找到如何让它在单独的进程中运行测试。因为您在上面描述的是一个 hack - 因为它将项目重建为不同的包名称,但只是暂时的?我理解正确吗?
  • 另外,如果我想要权限测试的话。它们需要与其他测试分开运行(因为如果它们在应用程序进程之外,其他测试将失败)。
  • @Blundell 您需要将applicationId 设置为测试包名称,以便gradle 将targetPackage 设置为测试包名称。这不是一个正确的解决方案,但我们需要弄清楚gradle是否允许覆盖targetPackage
  • 关于单独的测试,是的,您需要单独的测试包以获得单独的权限。您可以在此处查看GlobalSearch 测试代码结构。我不确定如何使用 gradle 来完成同样的任务。
  • 对,所以答案是测试需要在单独的进程中运行。但是对于 gradle,我们目前不知道如何做到这一点。 (您的 gradle 解决方案仅适用于命令行 [不是 AndroidStudio])谢谢我要戳 Android 工具团队。
猜你喜欢
  • 1970-01-01
  • 2021-07-08
  • 1970-01-01
  • 2020-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多