问题
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:
- Create a method that returns CommentsDataSource, e.g. getCommentsDataSource()
- Create a class that inherits CommentActivity
- Override the getCommentsDataSource() with a method that returns MockCommentsDataSource
- 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