How to inject a dependency when testing an Android activity without a third-party framework?

主宰稳场 提交于 2020-01-24 02:58:45

问题


I want to test an Android activity CommentActivity that normally constructs and uses an instance of CommentsDataSource (both are classes that I wrote).

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

I'm willing to create MockCommentsDataSource myself and would like to avoid using a third-party mocking framework. (Why? Because I'm a teaching trying to reduce the amount of information I need to cram into the semester and the amount of software my students need to install. I've seen other posts that recommend Guice, roboguice, and Spring.)

My question is how to pass a CommentsDataSource (or MockCommentsDataSource) to the Activity. It doesn't seem practical to make them Serializable or Parcelable, which they would have to be in order to be passed in through the Intent that starts CommentActivity. While I could easily pass in a debug flag, using it would require CommentActivity to know about MockCommentsDataSource, which is really none of its business (and in a separate application):

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));
      :
   }
   :
}

How should I inject MockCommentsDataSource into CommentActivity? FWIW, I'm using Eclipse and am developing for recent SDK versions.

One solution that occurs to me is to use the abstract factory pattern, since it would be relatively easy to make the factories serializable. Is that the best approach, given my constraints?


回答1:


Here are two ideas:

Not using factory:

This will probably work only for unit tests and not for integration tests:

  1. Create a method that returns CommentsDataSource, e.g. getCommentsDataSource()
  2. Create a class that inherits CommentActivity
  3. Override the getCommentsDataSource() with a method that returns MockCommentsDataSource
  4. Test the new class

Using factory:

As you mentioned, you can change the CommentActivity code to get the CommentsDataSource from a factory method. this way you can have the mock class returned by the factory method.

Hope this helps!




回答2:


I have a simple and ugly solution to offer, using a private static field to inject the dependency:

private static Client client;

and set the field value from the test using reflection:

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);
}

then, in i.e. onCreate(), use that "injected" test instance if the field is set and use the regular one otherwise.

Ugly, but requires only few changes relevant to testing to the class under test.



来源:https://stackoverflow.com/questions/22121911/how-to-inject-a-dependency-when-testing-an-android-activity-without-a-third-part

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!