从InstrumentationTestCase创建通知

时间:2015-12-11 10:17:25

标签: java android unit-testing notifications android-instrumentation

我想从单元测试中测试通知是否能够从资产中播放自定义声音。 测试不是为了验证任何东西,我把它写成一种快速的方式来演示一个功能而不会混淆主应用程序代码。

所以在测试项目中,我在/res/raw中添加了一个wav文件。我将在通知构建器中使用此URL:

Uri path = Uri.parse("android.resource://<main app package name>/testsound.wav");

该URL应该根据我在SO中阅读的问题工作。我们假设它有效。

现在因为我不想在主项目的/res/raw文件夹中包含测试wav文件,但是在测试项目中,我不得不从InstrumentationTestCase扩展我的单元测试我可以访问测试项目中的资源。

以下是代码:

    NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getContext());
    ...
    builder.setSound(path, AudioManager.STREAM_NOTIFICATION);
    ...
    NotificationManager notificationManager = (NotificationManager) getInstrumentation().getContext().getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(NOTIFICATION_ID, builder.build());

notify调用引发以下异常:

    java.lang.SecurityException: Calling uid 10198 gave package <main app package name> which is owned by uid 10199
    at android.os.Parcel.readException(Parcel.java:1540)
    at android.os.Parcel.readException(Parcel.java:1493)
    at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag(INotificationManager.java:611)
    at android.app.NotificationManager.notify(NotificationManager.java:187)
    at android.app.NotificationManager.notify(NotificationManager.java:140)
    ... 
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1873)

我已将此异常跟踪到NotificationManagerService类:

    void checkCallerIsSystemOrSameApp(String pkg) {
        int uid = Binder.getCallingUid();
        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
            return;
        }
        try {
            ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
                    pkg, 0, UserHandle.getCallingUserId());
            if (!UserHandle.isSameApp(ai.uid, uid)) {
                throw new SecurityException("Calling uid " + uid + " gave package"
                        + pkg + " which is owned by uid " + ai.uid);
            }
        } catch (RemoteException re) {
            throw new SecurityException("Unknown package " + pkg + "\n" + re);
        }
    }

显然,该例外与自定义声音没有任何关系,但事实是我们正在从InstrumentationTestCase创建通知。

有没有办法测试这个?我记得过去曾从AndroidTestCase创建过通知,但如果我这样做,那么我将无法访问测试wav文件。我可以使用wav创建一个jar并将jar放在测试项目的lib文件夹中,但这会隐藏文件,如果将来需要替换它,其他程序员可能很难找到它。

2 个答案:

答案 0 :(得分:2)

实际上,我对这个问题感到有些困惑。所以我写了一个小仪器测试。

为了断言,我将测试标记为仅在API 23上运行(getActiveNotifications之前似乎不可用),但它也适用于较旧的API。

诀窍是使用getTargetContext()代替getContext()

public final class MainActivityTest extends ActivityUnitTestCase<MainActivity> {

    public MainActivityTest() {
        super(MainActivity.class);
    }

    @TargetApi(Build.VERSION_CODES.M)
    public void testSendNotification() {
        final NotificationManager manager = (NotificationManager) getInstrumentation().getTargetContext().getSystemService(Context.NOTIFICATION_SERVICE);

        manager.cancel(42);
        assertEquals(0, manager.getActiveNotifications().length);

        final NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getTargetContext());
        builder.setContentTitle("Notification test")
                .setAutoCancel(true)
                .setContentText("Hello, Mister Smith")
                .setSmallIcon(R.drawable.ic_launcher_notification);

        manager.notify(42, builder.build());

        assertEquals(1, manager.getActiveNotifications().length);
    }
}

它就像一个魅力:

enter image description here

希望,这有帮助。

答案 1 :(得分:0)

我想到如何从AndroidTestCase获取声音。 wav文件已添加到测试项目的原始文件夹中,并未按预期包含在主项目中。

通知的网址如下:

Uri path = Uri.parse("android.resource://<test project package name>/" + R.raw.air_horn);

建造者的获得如下:

NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext());