【问题标题】:Unit testing: NoSuchMethodError while calling Notification.setLatestEventInfo()单元测试:调用 Notification.setLatestEventInfo() 时出现 NoSuchMethodError
【发布时间】:2015-12-23 03:37:27
【问题描述】:

请随意改进标题在这种特殊情况下我有点缺乏创意。

我正在实施一个用于检查通知的单元测试,我知道这几乎是不可能的,但我想检查一下我能将它自动化到什么程度。

我无法测试这行简单的代码:

Notification test = new NotificationCompat.Builder(context).build();

原因既愚蠢又简单。这里的代码将在内部执行:

public Notification build(Builder b, BuilderExtender extender) {
    Notification result = b.mNotification;
    result.setLatestEventInfo(b.mContext, b.mContentTitle,
            b.mContentText, b.mContentIntent);
    [...]

我遇到了这个异常:

Caused by: java.lang.NoSuchMethodError: android.app.Notification.setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V
    at android.support.v4.app.NotificationCompat$NotificationCompatImplBase.build(NotificationCompat.java:479)
    at android.support.v4.app.NotificationCompat$Builder.build(NotificationCompat.java:1561)

不难猜测,Google 人员在这里调用了一个方法,该方法在 Android Marshmallow SDK 中已被删除(或更恰当地用 @hide 注释)。我已经验证调用缺少最新的文档,但它是在 API 1 AFIK 中引入的。

我该如何解决这个问题?

我尝试过但被卡住的事情:

  • 覆盖回调,并在不调用该调用的情况下模拟该方法:
    我设法通过回调获得了Class<?>,但是我可以用哪种方法覆盖一个洞方法?我的意思是我需要修补调用它我不能只是模拟它。
  • 注入该调用,但如何注入?我可以直接覆盖它而不添加它。
  • 通过以下方式抑制呼叫:

    PowerMockito.spy(Notification.class);
    PowerMockito.suppress(PowerMockito.method(Notification.class, "setLatestEventInfo", Context.class, CharSequence.class, CharSequence.class, PendingIntent.class));
    

    由于我尝试踢出不存在的方法,因此无法正常工作。

  • 更改此测试的目标 SDK,但我该怎么做?

【问题讨论】:

    标签: android unit-testing mockito powermock


    【解决方案1】:

    解决方案比预期的要容易。我错过了默认情况下Build.VERSION.SDK_INT 的值0,因为它无法读取实际值。因此,支持库仅在存在此方法的平台上调用它。

    this answer 的帮助下。我只需要添加此代码:

    setFinalStatic(Build.VERSION.class.getDeclaredField("SDK_INT"), 23);
    

    我的代码有效。
    它仍然在其他地方崩溃,但通知已创建。哇哦!

    以及实际功能:

    public static void setFinalStatic(Field field, Object newValue) throws IllegalAccessException, NoSuchFieldException
    {
        field.setAccessible(true);
        // remove final modifier from field
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 2015-06-28
      • 1970-01-01
      相关资源
      最近更新 更多