Moxy
Moxy copied to clipboard
Mocking the presenter
Hello
I am trying to create a simple espresso UI test. My Activity has a:
@Override
public void updateResults(List<Model> modelList) {
adapter.update(modelList);
}
The presenter fetches the data on attachView()
and calls the activity/view doing:
getViewState().updateResults(modelList);
My espresso test looks like this:
@Test
public void myTest() {
Intent intent = new Intent();
intent.putExtra("xxx", "xxx");
activityRule.launchActivity(intent);
activityRule.getActivity().updateResults(createMockedList());
onView(withId(R.id.recycler_view))
// rest of the espresso code
}
Since I just want to test the UI, I would like to mock the presenter. If I leave the presenter as it is, attachView()
will be called and I don't want that.
I tried forcing the presenter using:
MvpFacade.getInstance().getPresenterStore().add("TravelerMessagesTestPresenter", new MockedMvpPresenter());
from ActivityTestRule:beforeActivityLaunched()
but you are reading the tag from the bundle and I can't modify that, just the intent.
Any idea on how to do it? If there is no way of doing this, would it be ok to add a "read tag from intent" in Moxy's MvpDelegate to contemplate this use case?
Thanks!
Hi,
Do you want to mock Presenter? You able to do something like this:
MvpFacade.getInstance().presenterStore = object : PresenterStore() {
override fun get(tag: String?): MvpPresenter<*> {
return yourMockPresenter
}
}
I have no other ideas =( I'll think yet
Ok, I got it working.
Code looks like this:
private MockedPresenterStore mockedPresenterStore;
private PresenterStore originalPresenterStore;
@Rule
public ActivityTestRule<MyActivity> activityRule =
new ActivityTestRule<MyActivity>(MyActivity.class, false, false) {
@Override
protected void beforeActivityLaunched() {
super.beforeActivityLaunched();
originalPresenterStore = MvpFacade.getInstance().getPresenterStore();
mockedPresenterStore = new MockedPresenterStore(new MockedMvpPresenter());
MvpFacade.getInstance().setPresenterStore(mockedPresenterStore);
}
@Override
protected void afterActivityLaunched() {
super.afterActivityLaunched();
MvpFacade.getInstance().setPresenterStore(originalPresenterStore);
}
};
static class MockedPresenterStore extends PresenterStore {
private final MvpPresenter mockedMvpPresenter;
public MockedPresenterStore(MvpPresenter mockedMvpPresenter) {
this.mockedMvpPresenter = mockedMvpPresenter;
}
@Override
public MvpPresenter get(String tag) {
return mockedMvpPresenter;
}
}
// Presenter mock.
static class MockedMvpPresenter extends TravelerMessagesPresenter {
@Override
protected void onFirstViewAttach() {
// Do nothing
}
}
@Test
public void testMessagesShownInList() throws Throwable {
Intent intent = new Intent();
intent.putExtra("xx", "xx");
activityRule.launchActivity(intent);
activityRule.runOnUiThread(() -> activityRule.getActivity().updateResults(getMockedList()));
// espresso stuff here.
}
While this works, I don't like replacing the PresenterStore to be able to mock.
Are you against the idea of having a special tag stored in the intent and MvpDelegate reading from there just for testing purposes?
@senneco ping?
Hi @Macarse
I have some experimental code that allows you to specify tag's generator, but at the moment it's in development (because it's touch all moxy) :worried: I'll think about provides method wich will say presenter tag
@senneco Nice. Did you push a branch?
@Macarse no, it's only local experiments, because it's not ready absolutely =)