How can I swap test doubles at the scope of an Activity or a Fragment using Dagger 2?
<p><strong>EDIT: Watch out! I have deleted the old repository reffered to in this question. See my own answer to the question for a possible solution and feel free to improve it!</strong></p>

<p>I am refering to my post <a href="https://stackoverflow.com/questions/40405839/dagger-2-dependency-injection-in-android-testcase">here</a>. Now I came a little further. I am also refering to my two branches within my github Project:</p>

<ul>
<li>Experimental [branch no. 1] (repository deleted)</li>
<li>Experimental [branch no. 2] (repository deleted)</li>
</ul>

<p>In the old post I tried to swap components to test-components within an Instrumentation Test. This works now if I have an <code>ApplicationComponent</code>, being in singleton scope. But it does <strong>not</strong> work if I have an <code>ActivityComponent</code> with a self defined <code>@PerActivity</code> scope. The problem is <strong>not</strong> the scope but the swapping of the Component to the TestComponent.</p>

<p>My <code>ActivityComponent</code> has an <code>ActivityModule</code>:</p>

<pre><code>@PerActivity
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    // TODO: Comment this out for switching back to the old approach
    void inject(MainFragment mainFragment);
    // TODO: Leave that for witching to the new approach
    void inject(MainActivity mainActivity);
}
</code></pre>

<p><code>ActivityModule</code> provides a <code>MainInteractor</code></p>

<pre><code>@Module
public class ActivityModule {
    @Provides
    @PerActivity
    MainInteractor provideMainInteractor () {
        return new MainInteractor();
    }
}
</code></pre>

<p>My <code>TestActivityComponent</code> uses a <code>TestActivityModule</code>:</p>

<pre><code>@PerActivity
@Component(modules = TestActivityModule.class)
public interface TestActivityComponent extends ActivityComponent {
    void inject(MainActivityTest mainActivityTest);
}
</code></pre>

<p><code>TestActvityModule</code> provides a <code>FakeInteractor</code> :</p>

<pre><code>@Module
public class TestActivityModule {
    @Provides
    @PerActivity
    MainInteractor provideMainInteractor () {
        return new FakeMainInteractor();
    }
}
</code></pre>

<p>My <code>MainActivity</code> has a <code>getComponent()</code> method and a <code>setComponent()</code> method. With the latter you can swap the component to a test component within the Instrumentation Test. Here is the activity:</p>

<pre><code>public class MainActivity extends BaseActivity implements MainFragment.OnFragmentInteractionListener {


    private static final String TAG = "MainActivity";
    private Fragment currentFragment;
    private ActivityComponent activityComponent;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initializeInjector();


        if (savedInstanceState == null) {
            currentFragment = new MainFragment();
            addFragment(R.id.fragmentContainer, currentFragment);
        }

    }

    private void initializeInjector() {
        Log.i(TAG, "injectDagger initializeInjector()");

        activityComponent = DaggerActivityComponent.builder()
                .activityModule(new ActivityModule())
                .build();
        activityComponent.inject(this);
    }

    @Override
    public void onFragmentInteraction(final Uri uri) {

    }

    ActivityComponent getActivityComponent() {
        return activityComponent;
    }

    @VisibleForTesting
    public void setActivityComponent(ActivityComponent activityComponent) {
        Log.w(TAG, "injectDagger Only call this method to swap test doubles");
        this.activityComponent = activityComponent;
    }
} 
</code></pre>

<p>As you see this activity uses a <code>MainFragment</code>. In <code>onCreate()</code> of the fragment the component is injected:</p>

<pre><code>public class MainFragment extends BaseFragment implements MainView {

    private static final String TAG = "MainFragment";
    @Inject
    MainPresenter mainPresenter;
    private View view;

    public MainFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "injectDagger onCreate()");
        super.onCreate(savedInstanceState);
        // TODO: That approach works
//        ((AndroidApplication)((MainActivity) getActivity()).getApplication()).getApplicationComponent().inject(this);
        // TODO: This approach is NOT working, see MainActvityTest
        ((MainActivity) getActivity()).getActivityComponent().inject(this);
    }
}
</code></pre>

<p>And then in the test I swap the <code>ActivityComponent</code> with the <code>TestApplicationComponent</code>:</p>

<pre><code>public class MainActivityTest{

    @Rule
    public ActivityTestRule&lt;MainActivity&gt; mActivityRule = new ActivityTestRule(MainActivity.class, true, false);

    private MainActivity mActivity;
    private TestActivityComponent mTestActivityComponent;

    // TODO: That approach works
//    private TestApplicationComponent mTestApplicationComponent;
//
//    private void initializeInjector() {
//        mTestApplicationComponent = DaggerTestApplicationComponent.builder()
//                .testApplicationModule(new TestApplicationModule(getApp()))
//                .build();
//
//        getApp().setApplicationComponent(mTestApplicationComponent);
//        mTestApplicationComponent.inject(this);
//    }

    // TODO: This approach does NOT work because mActivity.setActivityComponent() is called after MainInteractor has already been injected!
    private void initializeInjector() {
        mTestActivityComponent = DaggerTestActivityComponent.builder()
                .testActivityModule(new TestActivityModule())
                .build();

        mActivity.setActivityComponent(mTestActivityComponent);
        mTestActivityComponent.inject(this);
    }

    public AndroidApplication getApp() {
        return (AndroidApplication) InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext();
    }
    // TODO: That approach works

//    @Before
//    public void setUp() throws Exception {
//
//        initializeInjector();
//        mActivityRule.launchActivity(null);
//        mActivity = mActivityRule.getActivity();
//    }

    // TODO: That approach does not works because mActivity.setActivityComponent() is called after MainInteractor has already been injected!
    @Before
    public void setUp() throws Exception {
        mActivityRule.launchActivity(null);
        mActivity = mActivityRule.getActivity();
        initializeInjector();
    }


    @Test
    public void testOnClick_Fake() throws Exception {
        onView(withId(R.id.edittext)).perform(typeText("John"));
        onView(withId(R.id.button)).perform(click());
        onView(withId(R.id.textview_greeting)).check(matches(withText(containsString("Hello Fake"))));
    }

    @Test
    public void testOnClick_Real() throws Exception {
        onView(withId(R.id.edittext)).perform(typeText("John"));
        onView(withId(R.id.button)).perform(click());
        onView(withId(R.id.textview_greeting)).check(matches(withText(containsString("Hello John"))));
    }

}
</code></pre>

<p>The Activity test runs but the wrong <code>Component</code> is used. This is because activities and fragments <code>onCreate()</code> is run before the component is swapped. </p>

<p>As you can see I have an commented old approach were I bind an <code>ApplicationComponent</code> to the application class. This works because I can build the dependency before starting the activity. But now with the <code>ActivityComponent</code> I have to launch the activity before initializing the injector. Because otherwise I could not set</p>

<pre><code>mActivity.setActivityComponent(mTestActivityComponent);
</code></pre>

<p>because <code>mActivity</code> would be null if would launch the activity after the initialization of the injector. (See <code>MainActivityTest</code>)</p>

<p>So how could I intercept the <code>MainActivity</code> and the <code>MainFragment</code> to use the <code>TestActivityComponent</code>?</p>