Trace
Trace

Reputation: 18889

Dagger2 disable AndroidInjection.inject(this); for instrumentation test

With the latest Dagger2 we can inject dependencies through the following code:

public class BaseActivity extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
    }
}

Other activities that require DI inherit from this BaseClass. For my instrumentation tests, I don't want to use Dagger, I can just mock the objects.

My setup for the instrumentation test (I'm currently testing LoginActivity, which extends BaseActivity) is not special and as follows:

TestRunner:

public class LivefeedTestRunner extends AndroidJUnitRunner{
    @Override
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return super.newApplication(cl, TestApp.class.getName(), context);
    }
}

TestApp:

public class TestApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
    }
}

The problem is that running the instrumentation test results in an error caused by:

Caused by: java.lang.RuntimeException: com.example.kimgysen.livefeed_v002.TestApp does not implement dagger.android.HasActivityInjector at dagger.android.AndroidInjection.inject(AndroidInjection.java:48) at com.example.kimgysen.livefeed_v002.ui.BaseActivity.onCreate(BaseActivity.java:12) at com.example.kimgysen.livefeed_v002.ui.login.LoginActivity.onCreate(LoginActivity.java:32) at android.app.Activity.performCreate(Activity.java:6237) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107) at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:624) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369) ... 9 more

Which points to the following line:

public class BaseActivity extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this); // <-- this line 
        super.onCreate(savedInstanceState);
    }
}

Any idea how I can easily bypass this? In my app itself, I implement dagger.android.HasActivityInjector, but I don't need it for my instrumentation test.

Upvotes: 1

Views: 1047

Answers (2)

makovkastar
makovkastar

Reputation: 5020

There is an alternative solution in the android-architecture-components samples on Github.

They inject the activities trough ActivityLifecycleCallbacks. For instrumented tests they use a TestApp that does not register ActivityLifecycleCallbacks so it injects nothing.

See https://stackoverflow.com/a/48101811/1552622.

Upvotes: 0

Trace
Trace

Reputation: 18889

I solved the problem by creating a fake activityInjector as suggested in the following post:
https://github.com/google/dagger/blob/master/javatests/dagger/android/AndroidInjectionTest.java#L60

(equivalent for fakeActivityInjector)

public class TestApp extends Application implements HasActivityInjector {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return fakeActivityInjector("injected by app");
    }

    public static class InjectableActivity extends Activity {
        String tag;
    }

    private static AndroidInjector<Activity> fakeActivityInjector(String tag) {
        return instance -> {
            if (instance instanceof InjectableActivity) {
                ((InjectableActivity) instance).tag = tag;
            }
        };
    }
}

Upvotes: 4

Related Questions