Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to putExtra data using newest ActivityScenarioRule/ActivityScenario?[Espresso/Jetpack]

There were added new classes to test Activities, such as ActivityScenarioRule and ActivityScenario And there is no documentation how to use them when you want put some extra data.

For now I've found two working ways, in short:

1) Use ActivityScenarioRule and put your extra in the method with @Before annotation using #onActivity. But, there would be unnecessary data for some test cases.

2) Second, use ActivityScenario with #launch(Class activityClass) when you dont need extra and #launch(Intent startActivityIntent) when you want put extra. But, this time I loose an ability to use #onActivity where can be placed common for all test cases

P.S. this is my first time of android testing :)

like image 752
Akbolat SSS Avatar asked Jan 14 '19 10:01

Akbolat SSS


People also ask

How do you get activity from ActivityScenarioRule?

ActivityScenarioRule launches a given activity before the test starts and closes after the test. You can access the ActivityScenario instance via getScenario() . You may finish your activity manually in your test, it will not cause any problems and this rule does nothing after the test in such cases.

What is activity scenario?

ActivityScenario provides APIs to start and drive an Activity's lifecycle state for testing. It works with arbitrary activities and works consistently across different versions of the Android framework. The ActivityScenario API uses Lifecycle. State extensively.

What is activity test rule?

The Activity can be manually launched with launchActivity(Intent) , and manually finished with finishActivity() . If the Activity is running at the end of the test, the test rule will finish it.


4 Answers

What I've decided to do - marginally simpler than the other answers.

lateinit var scenario: ActivityScenario<MyActivity>

@After
fun cleanup() {
    scenario.close()
}

@Test
fun myTest() {
    val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
        .putExtra("key", "value")
    scenario = launchActivity(intent)
    // Your test code goes here.
}

You'll also need to add the below dependency to your gradle file

androidTestImplementation 'androidx.test:core-ktx:1.2.0'

Reference: https://medium.com/stepstone-tech/better-tests-with-androidxs-activityscenario-in-kotlin-part-1-6a6376b713ea

like image 169
Inti Avatar answered Nov 11 '22 06:11

Inti


I was able to solve this problem by using a static Intent in my test class. That way, my intent is instantiated before I pass it to my ActivityScenarioRule.

My espresso test class:

package your.package.tests.example;

import android.content.Intent;
import android.os.Bundle;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.espresso.assertion.ViewAssertions;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.matcher.ViewMatchers.*;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class TestExample {

    static Intent intent;
    static {
        intent = new Intent(ApplicationProvider.getApplicationContext(), YourActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("YOUR_BUNDLE_TAG", "YOUR_VALUE");
        intent.putExtras(bundle);
    }

    @Rule
    public ActivityScenarioRule<YourActivity> activityScenarioRule = new ActivityScenarioRule<>(intent);

    @Test
    public void yourTest() {
        onView(withId(R.id.simple_text)).check(ViewAssertions.matches(isDisplayed()));
    }
}

My espresso gradle dependencies:

dependencies {
    // Testing-only dependencies
    androidTestImplementation 'androidx.test:core:1.2.1-alpha02'
    androidTestImplementation 'androidx.test:core-ktx:1.2.1-alpha02'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2-alpha02'
    androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.2-alpha02'
    androidTestImplementation 'androidx.test:runner:1.3.0-alpha02'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02'
    androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0-alpha02'
    ...
}

References: Medium tutorial how to use espresso tests: https://medium.com/@heitorcolangelo/testes-no-android-com-espresso-parte-1-8d739672a235

like image 39
Jose Leles Avatar answered Nov 11 '22 05:11

Jose Leles


Personally i do it like that

lateinit var activityScenario: ActivityScenario<MyActivity>

@After
fun tearDown() {
    activityScenario.close()
}

@Test
fun myTest() {
    val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
    intent.putExtra("key", "value") //obviously use a const for key
    activityScenario = ActivityScenario.launch<MyActivity>(intent)

    activityScenario.onActivity {
        //whatever you like
    }
}
like image 33
Vaios Avatar answered Nov 11 '22 04:11

Vaios


From the Java doc on the deprecated ActivityTestRule it mentions:

For simple cases where you want to launch the Activity before each test and tear it down after each test (eg you are using ActivityTestRule(Class)), convert directly to ActivityScenarioRule.

If you need control over when to launch the Activity (eg you are using ActivityTestRule(Class, false, false), use ActivityScenario.launch. Its recommended to wrap the launch in a try-block, so the Activity is closed automatically.

To convert cases that need to pass custom data in the Intent, I've gone with the following:

final Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
final Intent intent = new Intent(targetContext, MyActivity.class);
intent.putExtra("foo", new Foo());

try (final ActivityScenario<MyActivity> scenario = ActivityScenario.launch(intent)) {
    /* Here you have access to scenario.onActivity() */
}

But, this time I loose an ability to use #onActivity where can be placed common for all test cases

I've decided to pull out common set-up into helper methods that I can call within the test as needed. Not as neat as a @Before block, but does the job.

like image 27
anotherdave Avatar answered Nov 11 '22 05:11

anotherdave