M Platt
M Platt

Reputation: 41

Android Test with Dagger mock inject constructor

Hi i've got a following Problem. I want to write android tests with espresso for the Ui and in order to have tests that are not flaky i want to mock my presenter.

I use Dagger in the App. My Configuration is as Following:

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
   //some injections
   //some providings
}

I have a Module for the Component

@Module
public class AppModule {
   //providings for component
}

then i have also a component for the activities with a module for the component

@PerActivity
@Component(dependencies = AppComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
    //inject activites
    //provide subcomponents for activites
}

then i have subcomponents for my pages

@PerActivity
@Subcomponent(modules = InfoModule.class)
public interface InfoComponent {
    void inject(DetailActivity activity);
}

and a module for the subcomponent

@Module
public class InfoModule {

    @Provides
    public DetailPresenter provideDetailPresenter(ShowDetailsUseCase showDetailsUseCase,
                                       OtherUseCase getPoisUseCase,
                                       AccountManager accountManager, Navigator
                                               navigator) {
        return new DetailPresenter(showDetailsUseCase, otherUseCase, accountManager, navigator);
    }
}

and then the detail Activity Injects the DetailPresenter

public class DetailActivity extends BaseActivity {

    @Inject
    DetailPresenter mPresenter;

    InfoComponent mComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mComponent = getActivityComponent().provideInfoModule(new InfoModule());
        mComponent.inject(this);
        mPresenter.bindView(this);
        mPresenter.onCreate(new PresenterBundle(getIntent().getExtras(), savedInstanceState));
    }
    //functionality of detailActiviy
}

then i have the presenter which uses constructor injection

public class DetailPresenter extends BasePresenter {


    private ShowDetailsUseCase mDetailsUseCase;
    private final OtherUseCase getPoisUseCase;

    private AccountManager accountManager;
    private Navigator navigator;

    @Inject
    public DetailPresenter(ShowDetailsUseCase getDetailsUseCase, OtherUseCase getPoisUseCase,
    AccountManager
    accountManager, Navigator navigator) {
        this.mDetailsUseCase = getDetailsUseCase;
        this.getPoisUseCase = gotherUseCase;
        this.accountManager = accountManager;
        this.navigator = navigator;
    }

    @Override
    public void onCreate(@Nullable PresenterBundle bundle) {
        super.onCreate(bundle);
        //other things to do on initialization
        ((DetailView) getView()).showDetails(getDetailsFromUseCase());

    }
}

Now in the test i want to do mock the presenter:

@RunWith(AndroidJUnit4.class)
public class DetailActivityTest {

    @Rule
    public final ActivityTestRule<DetailActivity> main = new ActivityTestRule<DetailActivity>(DetailActivity.class, true, false);

    @Rule
    public final DaggerMockRule<AppComponent> rule=new EspressoDaggerMockRule();

    @Mock
    DetailPresenter presenter; //does not work because @Inject constructor


    @Test
    public void locationTest() {

        Details details = generateDetails();

        launchActivity();

        doAnswer(answer -> {
                    activity.showDetails(details);
                    return null;
                }

        ).when(presenter).onCreate(any());

        //espresso verify afterwards
    }
}

but if i try to mock the following error shows:

java.lang.RuntimeException: Error while trying to override objects:
a.b.c.ui.mvp.presenter.DetailPresenter
You must define overridden objects using a @Provides annotated method instead of using @Inject annotation

does someone have an idea how I am able to mock the presenter even with @Inject constructor and dependencies. I do not want to mock the data layer because then I have to mock database, apiClient, cacheData and so on. And some of the datalayer also have inject dependencies so i cannot mock them either.

Thank you in advance

Upvotes: 4

Views: 2163

Answers (1)

Fabio Collini
Fabio Collini

Reputation: 474

The DetailPresenter class is created in the InfoModule, so you don't need the Inject annotation. The error you get is because using DaggerMock you can replace only the objects created in a module. In your example you are already creating it in a module, you just need to remove the Inject annotation.

Upvotes: 1

Related Questions