Stay organized with collections
Save and categorize content based on your preferences.
Testing your app is a necessary part of the Cast development process. Your app
should comply with the Cast UX
Guidelines and Design
Checklist to ensure
users have a consistent Cast experience.
For Android apps, leverage the UI
Automator and
Espresso testing
frameworks to simulate user interactions on your app and run your UI tests in an
automated and repeatable way. To learn more about automated UI tests, see
Automate user interface
tests.
This guide describes how to add automated UI tests to your Android sender app.
Set up the test environment
Android Studio is recommended
for building and running your app and tests.
On the physical device used for testing, under Settings > Developer options,
turn off the following system animations:
By default, Android Studio provides a source code directory at
src/androidTest/java/ to place your instrumented and UI tests. For more
information, see Test types and
location.
To test if a Cast icon is displayed on the app:
packagecom.example.package;importorg.junit.Rule;importorg.junit.Test;importorg.junit.runner.RunWith;importandroidx.mediarouter.app.MediaRouteButton;importandroidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;importandroidx.test.rule.ActivityTestRule;import staticandroidx.test.espresso.Espresso.onView;import staticandroidx.test.espresso.assertion.ViewAssertions.matches;import staticandroidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;import staticandroidx.test.espresso.matcher.ViewMatchers.isDisplayed;@RunWith(AndroidJUnit4ClassRunner.class)publicclassMyCastUITest{@RulepublicActivityTestRule<MainActivity>mActivityRule=newActivityTestRule<>(MainActivity.class);@TestpublicvoidtestCastButtonDisplay()throwsInterruptedException{// wait for Cast buttonThread.sleep(2000);onView(isAssignableFrom(MediaRouteButton.class)).check(matches(isDisplayed()));}}
Test Cast connection
This example shows how to simulate user actions connecting to a Cast device:
importandroidx.test.platform.app.InstrumentationRegistry;importandroidx.test.uiautomator.UiDevice;importandroidx.test.uiautomator.UiObjectNotFoundException;importandroidx.test.uiautomator.UiSelector;import staticandroidx.test.espresso.action.ViewActions.click;import staticandroidx.test.espresso.matcher.ViewMatchers.withId;@RunWith(AndroidJUnit4ClassRunner.class)publicclassMyCastUITest{@RulepublicActivityTestRule<MainActivity>mActivityRule=newActivityTestRule<>(MainActivity.class);/** * Connecting to Cast device * - Open Cast menu dialog when tapping the Cast icon * - Select target Cast device and connect * - Assert the Cast state is connected */@TestpublicvoidtestConnectToCastDevice()throwsInterruptedException,UiObjectNotFoundException{// wait for Cast button readyThread.sleep(2000);// click on Cast icon and show a dialogonView(isAssignableFrom(MediaRouteButton.class)).perform(click());onView(withId(R.id.action_bar_root)).check(matches(isDisplayed()));// select target Cast device to connectUiDevicemDevice=UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());mDevice.findObject(newUiSelector().text(TARGET_DEVICE)).click();// assert the Cast state is connectedassertCastStateIsConnected(MAX_TIMEOUT_MS);}}
The Cast session and connection state can be retrieved by executing a call on
the application's main thread:
importandroid.content.Context;importandroid.os.SystemClock;importcom.google.android.gms.cast.framework.CastContext;importcom.google.android.gms.cast.framework.CastSession;importcom.google.android.gms.cast.framework.SessionManager;import staticorg.junit.Assert.assertTrue;@RunWith(AndroidJUnit4ClassRunner.class)publicclassMyCastUITest{privateCastContextmCastContext;privateCastSessionmCastSession;privateSessionManagermSessionManager;privatebooleanisCastConnected;@RulepublicActivityTestRule<MainActivity>mActivityRule=newActivityTestRule<>(MainActivity.class);/** * Connecting to Cast device */@TestpublicvoidtestConnectToCastDevice()throwsInterruptedException,UiObjectNotFoundException{......// assert the Cast state is connectedassertCastStateIsConnected(MAX_TIMEOUT_MS);}/** * Check connection status from Cast session */privatevoidassertCastStateIsConnected(longtimeout)throwsInterruptedException{longstartTime=SystemClock.uptimeMillis();isCastConnected=false;while(!isCastConnected && SystemClock.uptimeMillis()-startTime < timeout){Thread.sleep(500);// get cast instance and cast session from the app's main threadInstrumentationRegistry.getInstrumentation().runOnMainSync(newRunnable(){@Overridepublicvoidrun(){ContextmTargetContext=InstrumentationRegistry.getInstrumentation().getTargetContext();mCastContext=CastContext.getSharedInstance(mTargetContext);mSessionManager=mCastContext.getSessionManager();mCastSession=mSessionManager.getCurrentCastSession();isCastConnected=mCastSession.isConnected();}});}assertTrue(isCastConnected);}}
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-14 UTC."],[[["\u003cp\u003eAndroid sender apps should be tested for UI compliance with Cast UX Guidelines and Design Checklist.\u003c/p\u003e\n"],["\u003cp\u003eUI Automator and Espresso frameworks are recommended for simulating user interactions and automated UI testing.\u003c/p\u003e\n"],["\u003cp\u003eAndroid Studio facilitates building, running tests, and provides a dedicated directory (\u003ccode\u003esrc/androidTest/java/\u003c/code\u003e) for instrumented and UI tests.\u003c/p\u003e\n"],["\u003cp\u003eSample Cast test cases are available in the CastVideos-android repository on GitHub for reference.\u003c/p\u003e\n"],["\u003cp\u003eThe UI Automator framework necessitates Android 4.3 (API level 18) or higher for compatibility.\u003c/p\u003e\n"]]],["To test Cast functionality in Android apps, developers should use UI Automator and Espresso frameworks for automated, repeatable UI tests. Ensure compliance with Cast UX guidelines. Set up testing in Android Studio, disabling system animations on the test device. Use `src/androidTest/java/` for test code. Key actions include checking for the Cast icon's visibility, simulating connection to a Cast device, and verifying the Cast state using `CastContext` and `CastSession` through the app's main thread.\n"],null,["Testing your app is a necessary part of the Cast development process. Your app\nshould comply with the [Cast UX\nGuidelines](https://developers.google.com/cast/docs/ux_guidelines) and [Design\nChecklist](https://developers.google.com/cast/docs/design_checklist/) to ensure\nusers have a consistent Cast experience.\n\nFor Android apps, leverage the [UI\nAutomator](https://developer.android.com/training/testing/ui-automator) and\n[Espresso](https://developer.android.com/training/testing/espresso/) testing\nframeworks to simulate user interactions on your app and run your UI tests in an\nautomated and repeatable way. To learn more about automated UI tests, see\n[Automate user interface\ntests](https://developer.android.com/training/testing/ui-testing).\n\nThis guide describes how to add automated UI tests to your Android sender app.\n| **Note:** The sample Cast test cases are also available in the GitHub [CastVideos-android](https://github.com/googlecast/CastVideos-android#automated-ui-testing-on-cast-sender-app) sample app.\n\nSet up the test environment\n\n[Android Studio](https://developer.android.com/studio/index.html) is recommended\nfor building and running your app and tests.\n\nOn the physical device used for testing, under **Settings \\\u003e Developer options**,\nturn off the following system animations:\n\n- Window animation scale\n- Transition animation scale\n- Animator duration scale\n\nExample Gradle build file \n\n apply plugin: 'com.android.application'\n\n android {\n compileSdkVersion 34\n\n defaultConfig {\n applicationId \"com.example.package\"\n minSdkVersion 23\n targetSdkVersion 34\n testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n }\n }\n\n dependencies {\n ...\n\n testImplementation 'junit:junit:4.12'\n androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'\n androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'\n androidTestImplementation 'androidx.test:runner:1.1.1'\n androidTestImplementation 'androidx.test:rules:1.1.1'\n }\n\n| **Note:** The UI Automator framework requires **Android 4.3 (API level 18)** or higher.\n\nAdd the first Cast UI test\n\nBy default, Android Studio provides a source code directory at\n`src/androidTest/java/` to place your instrumented and UI tests. For more\ninformation, see [Test types and\nlocation](https://developer.android.com/studio/test#test_types_and_location).\n\nTo test if a Cast icon is displayed on the app: \n\n package com.example.package;\n\n import org.junit.Rule;\n import org.junit.Test;\n import org.junit.runner.RunWith;\n\n import androidx.mediarouter.app.MediaRouteButton;\n import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;\n import androidx.test.rule.ActivityTestRule;\n\n import static androidx.test.espresso.Espresso.onView;\n import static androidx.test.espresso.assertion.ViewAssertions.matches;\n import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;\n import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;\n\n @RunWith(AndroidJUnit4ClassRunner.class)\n public class MyCastUITest {\n\n @Rule\n public ActivityTestRule\u003cMainActivity\u003e mActivityRule =\n new ActivityTestRule\u003c\u003e(MainActivity.class);\n\n @Test\n public void testCastButtonDisplay() throws InterruptedException {\n // wait for Cast button\n Thread.sleep(2000);\n\n onView(isAssignableFrom(MediaRouteButton.class)).check(matches(isDisplayed()));\n }\n }\n\nTest Cast connection\n\nThis example shows how to simulate user actions connecting to a Cast device: \n\n import androidx.test.platform.app.InstrumentationRegistry;\n import androidx.test.uiautomator.UiDevice;\n import androidx.test.uiautomator.UiObjectNotFoundException;\n import androidx.test.uiautomator.UiSelector;\n\n import static androidx.test.espresso.action.ViewActions.click;\n import static androidx.test.espresso.matcher.ViewMatchers.withId;\n\n @RunWith(AndroidJUnit4ClassRunner.class)\n public class MyCastUITest {\n\n @Rule\n public ActivityTestRule\u003cMainActivity\u003e mActivityRule =\n new ActivityTestRule\u003c\u003e(MainActivity.class);\n\n /**\n * Connecting to Cast device\n * - Open Cast menu dialog when tapping the Cast icon\n * - Select target Cast device and connect\n * - Assert the Cast state is connected\n */\n @Test\n public void testConnectToCastDevice()\n throws InterruptedException, UiObjectNotFoundException {\n\n // wait for Cast button ready\n Thread.sleep(2000);\n\n // click on Cast icon and show a dialog\n onView(isAssignableFrom(MediaRouteButton.class))\n .perform(click());\n onView(withId(R.id.action_bar_root))\n .check(matches(isDisplayed()));\n\n // select target Cast device to connect\n UiDevice mDevice = UiDevice.getInstance(\n InstrumentationRegistry.getInstrumentation());\n mDevice.findObject(new UiSelector().text(TARGET_DEVICE)).click();\n\n // assert the Cast state is connected\n assertCastStateIsConnected(MAX_TIMEOUT_MS);\n }\n }\n\nThe Cast session and connection state can be retrieved by executing a call on\nthe application's main thread: \n\n import android.content.Context;\n import android.os.SystemClock;\n\n import com.google.android.gms.cast.framework.CastContext;\n import com.google.android.gms.cast.framework.CastSession;\n import com.google.android.gms.cast.framework.SessionManager;\n\n import static org.junit.Assert.assertTrue;\n\n @RunWith(AndroidJUnit4ClassRunner.class)\n public class MyCastUITest {\n private CastContext mCastContext;\n private CastSession mCastSession;\n private SessionManager mSessionManager;\n private boolean isCastConnected;\n\n @Rule\n public ActivityTestRule\u003cMainActivity\u003e mActivityRule =\n new ActivityTestRule\u003c\u003e(MainActivity.class);\n\n /**\n * Connecting to Cast device\n */\n @Test\n public void testConnectToCastDevice()\n throws InterruptedException, UiObjectNotFoundException {\n ......\n\n // assert the Cast state is connected\n assertCastStateIsConnected(MAX_TIMEOUT_MS);\n }\n\n /**\n * Check connection status from Cast session\n */\n private void assertCastStateIsConnected(long timeout)\n throws InterruptedException {\n\n long startTime = SystemClock.uptimeMillis();\n isCastConnected = false;\n\n while (!isCastConnected && SystemClock.uptimeMillis() - startTime \u003c timeout) {\n\n Thread.sleep(500);\n\n // get cast instance and cast session from the app's main thread\n InstrumentationRegistry.getInstrumentation().runOnMainSync(\n new Runnable() {\n @Override\n public void run() {\n Context mTargetContext =\n InstrumentationRegistry.getInstrumentation().getTargetContext();\n mCastContext =\n CastContext.getSharedInstance(mTargetContext);\n mSessionManager = mCastContext.getSessionManager();\n mCastSession =\n mSessionManager.getCurrentCastSession();\n isCastConnected = mCastSession.isConnected();\n }\n }\n );\n }\n\n assertTrue(isCastConnected);\n }\n }"]]