Last active
October 13, 2020 14:43
-
-
Save saxophone/961ceceea43f8501cbaf to your computer and use it in GitHub Desktop.
Use Android Espresso to test that your Activity finishes with the expected result.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Intent; | |
import android.os.Bundle; | |
import android.support.v7.app.AppCompatActivity; | |
import org.hamcrest.Description; | |
import org.hamcrest.Matcher; | |
import org.hamcrest.TypeSafeMatcher; | |
import static android.support.test.InstrumentationRegistry.getInstrumentation; | |
import static org.hamcrest.MatcherAssert.assertThat; | |
/** | |
* A test-specific activity that immediately starts another activity and listens for that subject's | |
* results | |
*/ | |
public class ResultTestActivity extends AppCompatActivity { | |
/** | |
* An interface that defines all of the variables involved in testing that an activity's | |
* results are as expected | |
*/ | |
public interface ActivityResultTest { | |
/** | |
* @return the intent with the appropriate extras that will start your subject activity | |
*/ | |
Intent getSubjectIntent(); | |
/** | |
* Perform the necessary UI actions necessary to trigger the target activity finishing with | |
* a result. | |
*/ | |
void triggerActivityResult(); | |
/** | |
* @return a matcher for the result test activity to match the target activity's result | |
*/ | |
Matcher<ResultTestActivity> getActivityResultMatcher(); | |
} | |
private final static String EXTRA_START_ACTIVITY_INTENT = "extraStartActivityIntent"; | |
private final static int REQUEST_CODE = 9999; | |
private int mResultCode; | |
private Intent mResultData; | |
/** | |
* A simple static method to extract intent creation for this test activity | |
* | |
* @param subjectIntent The intent that will start the activity being tested. | |
*/ | |
public static Intent createIntent(Intent subjectIntent) { | |
Intent intent = new Intent(getInstrumentation().getTargetContext(), ResultTestActivity.class); | |
intent.putExtra(EXTRA_START_ACTIVITY_INTENT, subjectIntent); | |
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | |
return intent; | |
} | |
@Override | |
public void onActivityResult(int requestCode, int resultCode, Intent data) { | |
super.onActivityResult(requestCode, resultCode, data); | |
if (requestCode == REQUEST_CODE) { | |
mResultCode = resultCode; | |
mResultData = data; | |
} | |
} | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
if (savedInstanceState == null) { | |
Intent subjectIntent = getIntent().getParcelableExtra(EXTRA_START_ACTIVITY_INTENT);] | |
startActivityForResult(subjectIntent, REQUEST_CODE); | |
} | |
} | |
/** | |
* Execute the steps necessary for testing whether a subject activity finishes with the | |
* activity results expected | |
* | |
* @param test Define the subject's intent, actions required to finish the subject activity, | |
* and a matcher for ResultTestActivity, likely receivedExpectedResult(); | |
*/ | |
public static void runActivityResultTest(ActivityResultTest test) { | |
// Start an instance of ActivityResultTest, using the subject Activity's intent as an extra | |
getInstrumentation().startActivitySync(test.getSubjectIntent()); | |
// Perform actions that will cause your subject to finish with a result | |
test.triggerActivityResult(); | |
// If you have the Developer option "Don't keep activities" enabled on your testing device, | |
// the instance of ResultTestActivity from startActivitySync() will be different from the | |
// ResultTestActivity that will actually receive your subject's results. Since it doesn't | |
// matter which instance of ResultTestActivity gets results, we use a testing helper method | |
// to get the current activity, which we assume will be a ResultTestActivity | |
ResultTestActivity resultTestActivity = (ResultTestActivity) TestUtils.getCurrentActivity(); | |
// Match the current ResultTestActivity against your expectations for the results as | |
// defined in the input ActivityResultTest | |
assertThat(resultTestActivity, test.getActivityResultMatcher()); | |
// resultTestActivity has been created in this method and if we don't finish it here, it | |
// will continue to exist on your device. There's no need for that, so kill it. | |
resultTestActivity.finish(); | |
} | |
/** | |
* A matcher that determines if the ResultTestActivity has received the activity results expected | |
* from your subject activity | |
* | |
* @param resultCodeMatcher Matcher for the result code | |
* @param resultDataMatcher Matcher for the data in the resultant Intent | |
*/ | |
public static Matcher<ResultTestActivity> receivedExpectedResult(final Matcher<Integer> resultCodeMatcher, final Matcher<Intent> resultDataMatcher) { | |
return new TypeSafeMatcher<ResultTestActivity>() { | |
@Override | |
protected boolean matchesSafely(ResultTestActivity item) { | |
return resultCodeMatcher.matches(item.mResultCode) && resultDataMatcher.matches(item.mResultData); | |
} | |
@Override | |
public void describeTo(Description description) { | |
description.appendText("with result code=").appendDescriptionOf(resultCodeMatcher); | |
description.appendText(" and with intent=").appendDescriptionOf(resultDataMatcher); | |
} | |
}; | |
} | |
@Override | |
public String toString() { | |
return "Result Activity with result code=" + mResultCode + " and request data=" + mResultData; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Activity; | |
import android.os.Looper; | |
import android.support.test.runner.lifecycle.ActivityLifecycleMonitor; | |
import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; | |
import android.support.test.runner.lifecycle.Stage; | |
import java.util.Collection; | |
import static android.support.test.InstrumentationRegistry.getInstrumentation; | |
public class TestUtils { | |
public static Activity getCurrentActivity() { | |
if (Looper.myLooper() == Looper.getMainLooper()) { | |
return getCurrentActivityOnMainThread(); | |
} else { | |
final Activity[] topActivity = new Activity[1]; | |
getInstrumentation().runOnMainSync(new Runnable() { | |
@Override | |
public void run() { | |
topActivity[0] = getCurrentActivityOnMainThread(); | |
} | |
}); | |
return topActivity[0]; | |
} | |
} | |
private static Activity getCurrentActivityOnMainThread() { | |
ActivityLifecycleMonitor registry = ActivityLifecycleMonitorRegistry.getInstance(); | |
Collection<Activity> activities = registry.getActivitiesInStage(Stage.RESUMED); | |
return activities.iterator().hasNext() ? activities.iterator().next() : null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you very much for your resolution. It solves my problem 👍