fabioCollini / DaggerMock

A JUnit rule to easily override Dagger 2 objects
Apache License 2.0
1.16k stars 91 forks source link

How to mock Presenter method in Robolectric ? #79

Open development-codeface opened 6 years ago

development-codeface commented 6 years ago

First of all congratulations for the awesome library. I am new in mockito and robolectric, and just exploring the features. The following test case how we can write using robolectric.

public class MainActivityMockPresenterTest {

@Rule public EspressoDaggerMockRule rule = new EspressoDaggerMockRule();

@Rule public ActivityTestRule<MainActivity> activityRule = new ActivityTestRule<>(MainActivity.class, false, false);

@Mock MainPresenter presenter;

@Mock SnackBarManager snackBarManager;

@Test
public void testOnCreate() {
    final MainActivity activity = activityRule.launchActivity(null);

    doAnswer(new Answer() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            activity.showText("Hello world");
            return null;
        }
    }).when(presenter).loadData();

    onView(withId(R.id.reload)).perform(click());

    onView(withId(R.id.text)).check(matches(withText("Hello world")));
}

@Test
public void testErrorOnCreate() {
    doAnswer(new Answer() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            snackBarManager.showMessage("Error!");
            return null;
        }
    }).when(presenter).loadData();

    activityRule.launchActivity(null);
    onView(withId(R.id.reload)).perform(click());

    onView(withId(R.id.text)).check(matches(withText("")));

    verify(snackBarManager).showMessage("Error!");
}

}

fabioCollini commented 6 years ago

Hi, I have never tried but it should work if you don't use standard Dagger subcomponent. Here you can find an example of a Robolectric test

https://github.com/fabioCollini/DaggerMock/blob/cc0b0acd98941cf432dad9f2771e79bc1e54d5c7/RealWorldAppInjector/src/test/java/it/cosenonjaviste/daggermock/robolectric/MainActivityTest.java

Let me know if you get some errors

development-codeface commented 6 years ago

i have tried this but mocking not happening still it show the original value. Please check my unit test case presenter

public class MainPresenter {

private MainService mainService;

private MainView view;

private SnackBarManager snackBarManager;

public MainPresenter(MainService mainService, MainView view, SnackBarManager snackBarManager) {
    this.mainService = mainService;
    this.view = view;
    this.snackBarManager = snackBarManager;
}

public void loadData() {
    try {
        String s = mainService.doSomething();
        view.showText(s);
    } catch (Exception e) {
        snackBarManager.showMessage((Activity) view, e.getMessage());
    }
}

public void testPresenter() {
    view.showText(textShow());
}

public String textShow(){
    return "ORGINAL";
}

}

TestRule

@RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class MainActivityTest {

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

@Mock
RestService restService;

MainActivity mainActivity;

@Mock
MainPresenter presenter;

@Test
public void testOnCreate() {
    when(restService.executeServerCall()).thenReturn(true);
    Robolectric.setupActivity(MainActivity.class);
}

@Test
public void testPresenter() {
    when(presenter.textShow()).thenReturn("MOCK");
    Robolectric.setupActivity(MainActivity.class);
    MainActivity mainActivityVal = Robolectric.setupActivity(MainActivity.class);
    TextView results = (TextView) mainActivityVal.findViewById(R.id.text);
    Button button = (Button) mainActivityVal.findViewById(R.id.reload);
    button.performClick();
    Assert.assertEquals("MOCK",mainActivityVal.presenter.textShow());
}

}

development-codeface commented 6 years ago

I have done one work around, please let me know this approach is acceptable. @Rule public final DaggerMockRule rule = new RobolectricMockTestRule();

@Mock
RestService restService;

MainActivity mainActivity;

@Mock
MainPresenter presenter;

@Before
public void beforemoke() {
    //when(restService.executeServerCall()).thenReturn(true);
    //mainActivity = Robolectric.setupActivity(MainActivity.class);
}

@Test
public void testOnCreate() {
    when(restService.executeServerCall()).thenReturn(true);
    Robolectric.setupActivity(MainActivity.class);
}

@Test
public void testPresenter() {
    when(presenter.textShow()).thenReturn("MOCKING");
    Robolectric.setupActivity(MainActivity.class);
    MainActivity mainActivityVal = Robolectric.setupActivity(MainActivity.class);
    TextView results = (TextView) mainActivityVal.findViewById(R.id.text);
    Button button = (Button) mainActivityVal.findViewById(R.id.reload);
    mainActivityVal.presenter = presenter;
    button.performClick();
    Assert.assertEquals("MOCKING",mainActivityVal.presenter.textShow());
}
fabioCollini commented 6 years ago

Hi, using this work around it works but it's not the best way to do it. I tried to implement the same test and it works, you can find it here: https://github.com/fabioCollini/DaggerMock/tree/master/RealWorldApp/src/test/java/it/cosenonjaviste/daggermock/realworldapp/robolectric

Looking at your example there is something strange, why are you invoking setupActivity twice?