Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a method of the tested Activity from a test using espresso and see its results

I'm creating and Android Application. I'm using Espresso for testing.

I've an Activity with the method:

public void render(Recipe recipe){
    //draw the recipe to the activity
}

I want to test that this method works correctly.

Not working solution 1

I've tested the following

@Test
public void viewPaintsRecipes() {
    final Activity activity = activityRule.launchActivity(new Intent());
    ((MainActivity)activity).render(Arrays.asList(new Recipe[]{recipe}));
    onView(withId(R.id.text)).check(matches(withText(recipe.toString())));
}

I get an Exception.

Only the original thread that created a view hierarchy can touch its views.

Not working solution 2

I've also tried to put the two lines inside a runnable runned by a Handler in the main thread, but the test hangs.

How can I acchieve this?

Notes

I attach the full test. Note that I use dagger and Mockito too.

@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTestWithMockPresenter {
    Recipe recipe = new Recipe("sampleTitle");
    @Rule
    public ActivityTestRule<MainActivity> activityRule = new ActivityTestRule(MainActivity.class, true, false);

    @Mock
    MainActivityPresenter mockPresenter;
    @Mock
    AndroidApplication mockContext;

    @Before
    public void insertMockedComponent(){
        MockitoAnnotations.initMocks(this);
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
        AndroidApplication app = (AndroidApplication) instrumentation.getTargetContext().getApplicationContext();
        MyModule mockedMyModule = new MyModule(mockContext){
            @Provides
            public MainActivityPresenter getMainActivityPresenter(){
                return mockPresenter;
            }
        };
        MyComponent component = DaggerMyComponent.builder().myModule(mockedMyModule).build();
        app.setComponent(component);
    }

    @Test
    public void viewPaintsRecipes() {
        final Activity activity = activityRule.launchActivity(new Intent());
        ((MainActivity)activity).render(Arrays.asList(new Recipe[]{recipe}));
        onView(withId(R.id.text)).check(matches(withText(recipe.toString())));
    }
}

Thanks

like image 880
Mateu Avatar asked Dec 15 '15 16:12

Mateu


1 Answers

This answer previously demonstrated how to call a method on the Activity under test by means of the ActivityTestRule.runOnUiThread(Runnable) method as follows:

@RunWith(AndroidJUnit4::class)
class MainActivityTest {

    @get:Rule var activityTestRule = ActivityTestRule(MainActivity::class.java)

    @Test
    fun recipe_is_rendered() {
        // When.
        activityTestRule.runOnUiThread { activityTestRule.activity.render(someRecipe) }

        // Then.
        // assert stuff about the recipe rendering here
    }
}

The ActivityTestRule class has since been deprecated and replaced by the ActivityScenarioRule class. The new, preferred way to call a method on the Activity under test is by means of the ActivityScenario.onActivity(ActivityAction) method as follows:

@RunWith(AndroidJUnit4::class)
class MainActivityTest {

    @get:Rule var activityScenarioRule = ActivityScenarioRule(MainActivity::class.java)

    @Test
    fun recipe_is_rendered() {
        // When.
        activityScenarioRule.scenario.onActivity { it.render(someRecipe) }

        // Then.
        // assert stuff about the recipe rendering here
    }
}

The only two dependencies I needed to add to my build.gradle file to do this were the following:

androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
like image 109
Adil Hussain Avatar answered Sep 19 '22 13:09

Adil Hussain