【问题标题】:Is it possible to find out if an Android application runs as part of an instrumentation test是否可以查明 Android 应用程序是否作为仪器测试的一部分运行
【发布时间】:2011-07-21 13:18:34
【问题描述】:

是否对应用程序进行运行时检查,以确定它是否作为仪器测试的一部分运行?

背景:我们的应用程序在启动时执行数据库同步。但这只有在定期启动时才会发生。它尤其会干扰测试数据库同步的仪器测试。不足为奇。

对于所有其他测试,这只是在浪费 CPU 周期。

【问题讨论】:

  • 你找到解决办法了吗?

标签: android unit-testing instrumentation


【解决方案1】:

一个更简单的解决方案是检查仅存在于测试类路径中的类,与 JUnit 4 一起使用(与使用 ActivityUnitTestCase 的解决方案不同)并且不需要向您的活动/服务发送自定义意图(这可能在某些情况下甚至不可能)

private boolean isTesting() {
    try {
        Class.forName("com.company.SomeTestClass");
        return true;
    } catch (ClassNotFoundException e) {
        return false;
    }
}

【讨论】:

    【解决方案2】:

    从 API 级别 11 开始,ActivityManager.isRunningInTestHarness() 方法可用。这可能会做你想做的事。

    【讨论】:

    • 无论我在运行测试还是应用配置,它都会返回 false
    • 这种方法基本上只在系统应用需要判断自己是否在某些平台测试工具中运行时才会用到。在这里查看我的错误:b.android.com/191171
    【解决方案3】:

    如果您使用的是 Robolectric,您可以执行以下操作:

    public boolean isUnitTest() {
            String device = Build.DEVICE;
            String product = Build.PRODUCT;
            if (device == null) {
                device = "";
            }
    
            if (product == null) {
                product = "";
            }
            return device.equals("robolectric") && product.equals("robolectric");
        }
    

    【讨论】:

      【解决方案4】:

      如果您使用的是 ActivityUnitTestCase,您可以使用 setApplication 设置自定义应用程序对象,并在其中设置一个标志来打开或关闭数据库同步?在我的博客上有一个使用自定义 Application 对象的示例:

      http://www.paulbutcher.com/2011/03/mock-objects-on-android-with-borachio-part-3/

      【讨论】:

      • 有趣。我已经有一个自定义应用程序,我可以轻松地在其中使用仪器测试标志。我明天试试。
      • 其他需要考虑的 - 您可以使用 RoboGuice code.google.com/p/roboguice 适当地注入您的数据库同步代码的仅测试版本(这实际上是我们在测试代码中所做的)。这里有我们设置的描述:swiftkey.net/blog/?p=496
      • 似乎只有 Activity 和 Service 测试用例有 setApplication 方法,而简单的 AndroidTestCase 不会。但无论如何,它们似乎运行良好。反正它似乎是唯一的开放。谢谢。
      • 如果您需要更灵活的东西,RoboGuice 肯定也可以。虽然设置它有很多麻烦:-)
      【解决方案5】:

      您可以将额外的意图传递给您的活动,表明它正在测试中。

      1) 在您的测试中,将“testMode”额外传递给您的活动:

      public void setUp() throws Exception {
          super.setUp();
      
          Intent activityIntent = new Intent();
          activityIntent.putExtra("testMode", true);
          setActivityIntent(activityIntent);
      }
      

      2) 在您的活动中,检查 testMode:

      Bundle extras = getIntent().getExtras();
      if (extras != null && extras.getBoolean("testMode")) {
          // disable your database sync
      }
      

      【讨论】:

      • 我使用这种方法进行一些遗留代码测试。我要指出的是,您的生产代码通常不应该以任何方式处理测试。
      【解决方案6】:

      d= (◕‿↼ ) Great answer,但如果某些库开发者(如我)想知道主机(或使用库的应用)是否正在测试,请尝试:

      import android.content.pm.ApplicationInfo;
      
      // ...
      
      private static int wasTestRun = 0xDEAD;
      
      /**
       * Should only be used to speed up testing (no behavior change).
       * @return true in tests, if Gradle has the right dependencies.
       */
      public static boolean isTestRun(@NonNull Context context) {
          if (wasTestRun != 0xDEAD) {
              return wasTestRun != 0;
          }
          // Ignore release builds (as App may be using JUnit by mistake).
          if (isDebuggable(context)) {
              try {
                  Class.forName("org.junit.runner.Runner");
                  wasTestRun = 1;
                  return true;
              } catch (ClassNotFoundException ignored) {
              }
          }
          wasTestRun = 0;
          return false;
      }
      
      public static boolean isDebuggable(@Nullable Context context) {
          return context != null && (context.getApplicationContext()
                  .getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
      }
      
      

      请注意,我没有使用任何 AtomicBoolean 或其他助手,因为它已经非常快了(锁定可能只会降低速度)。

      【讨论】:

        【解决方案7】:

        这对我有用,因为没有实际设备正在运行

        public static boolean isUnitTest() {
            return Build.BRAND.startsWith(Build.UNKNOWN) && Build.DEVICE.startsWith(Build.UNKNOWN) && Build.DEVICE.startsWith(Build.UNKNOWN) && Build.PRODUCT.startsWith(Build.UNKNOWN);
        }
        

        【讨论】:

        • 不确定是否需要为 DEVICE 测试两次。在我的带有 AS 2.3.3 和嵌入式 JDK、BRAND、DEVICE 和 PRODUCT 的测试机器上,测试变为:return (Build.BRAND == null || Build.BRAND.startsWith(Build.UNKNOWN)) && (Build. DEVICE == null || Build.DEVICE.startsWith(Build.UNKNOWN)) && (Build.PRODUCT == null || Build.PRODUCT.startsWith(Build.UNKNOWN));
        【解决方案8】:

        你可以试试这个

        if (isRunningTest == null) {
                isRunningTest = false;
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                List<StackTraceElement> list = Arrays.asList(stackTrace);
                for (StackTraceElement element : list) {
                    if (element.getClassName().startsWith("androidx.test.runner.MonitoringInstrumentation")) {
                        isRunningTest = true;
                        break;
                    }
                }
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-22
          • 2017-09-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多