【问题标题】:How to inject a dependency when testing an Android activity without a third-party framework?在没有第三方框架的情况下测试 Android 活动时如何注入依赖项?
【发布时间】:2014-03-01 23:38:51
【问题描述】:

我想测试一个 Android 活动 CommentActivity,它通常构造并使用 CommentsDataSource 的实例(这两个都是我编写的类)。

public class CommentActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    :
    CommentsDataSource = new CommentsDataSource(..);
    :
  }
  :
}

我愿意自己创建MockCommentsDataSource,并希望避免使用第三方模拟框架。 (为什么?因为我是一名教师,试图减少我需要在学期中填满的信息量以及我的学生需要安装的软件数量。我见过推荐 Guice、roboguice 和 Spring 的other posts。 )

我的问题是如何将CommentsDataSource(或MockCommentsDataSource)传递给活动。将它们设为SerializableParcelable 似乎不切实际,它们必须是它们才能通过以CommentActivity 开头的Intent 传递。虽然我可以轻松传入调试标志,但使用它需要CommentActivity 了解MockCommentsDataSource,这实际上与它无关(并且在单独的应用程序中):

public class CommentActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    :
    debugMode = getIntent().getBooleanExtra(DEBUG_MODE, false);

    // Get a connection to the database.
    final CommentsDataSource cds = (debugMode ? 
      new MockCommentsDataSource() :   // Abstraction violation
      new CommentsDataSource(this));
      :
   }
   :
}

我应该如何将MockCommentsDataSource 注入CommentActivity? FWIW,我正在使用 Eclipse 并正在为最新的 SDK 版本进行开发。

我想到的一个解决方案是使用抽象工厂模式,因为使工厂可序列化相对容易。考虑到我的限制,这是最好的方法吗?

【问题讨论】:

    标签: android dependency-injection android-testing abstract-factory


    【解决方案1】:

    这里有两个想法:

    不使用工厂:

    这可能仅适用于单元测试,不适用于集成测试:

    1. 创建一个返回 CommentsDataSource 的方法,例如getCommentsDataSource()
    2. 创建一个继承 CommentActivity 的类
    3. 使用返回 MockCommentsDataSource 的方法覆盖 getCommentsDataSource()
    4. 测试新类

    使用工厂:

    正如您所提到的,您可以更改 CommentActivity 代码以从工厂方法获取 CommentsDataSource。这样你就可以让工厂方法返回模拟类。

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      我提供了一个简单而丑陋的解决方案,使用私有静态字段来注入依赖项:

      private static Client client;

      并使用反射从测试中设置字段值:

      public static void setStaticFieldValue(final Class<?> clazz, 
              final String name, final Object value) throws Exception {
          final Field field = clazz.getDeclaredField(name);
          field.setAccessible(true);
          field.set(null, value);
      }
      

      然后,在即onCreate() 中,如果设置了该字段,则使用该“注入”测试实例,否则使用常规测试实例。

      丑陋,但只需要对被测类进行与测试相关的少量更改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-19
        • 2020-12-08
        • 2018-07-12
        • 1970-01-01
        • 2013-04-08
        • 2023-04-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多