Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Start specific conductor controller in (Espresso) Android instrumentation test

I'm writing Espresso tests for an app written using Conductor. I'd like to specify which controller to start for each test, so that I don't need to get Espresso to click through the app from the beginning Activity for each. Since there is only one Activity and not much on SO or google about Conductor the closest I could find was this question? Or is this not possible?

I've tried making the router static and adding a getter in an attempt to set a specific root for testing with no success.

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

In MainActivity:

public static Router getRouter() {
    return router;
}

In Instrumentation Test:

@Rule
public ActivityTestRule<MainActivity> testRule = new ActivityTestRule<>(MainActivity.class);

@Before
public void setUp() {
    Router router = testRule.getActivity().getRouter();
    router.setRoot(RouterTransaction.with(new ControllerIwantToTest()));
}

@Test
public void titleIsDisplayed() {
    onView(withText("My Controllers Title")).check(matches(isDisplayed()));
}
like image 440
Kai Avatar asked Apr 11 '17 05:04

Kai


People also ask

What is instrumentation test in Android?

Instrumented tests run on Android devices, whether physical or emulated. As such, they can take advantage of the Android framework APIs. Instrumented tests therefore provide more fidelity than local tests, though they run much more slowly.


1 Answers

If anyone else comes across the same issue, I've solved the problem by doing the following:

@RunWith(AndroidJUnit4.class)
public class NoBundleControllerEspressoTest {

private Router router;

@Rule
public ActivityTestRule<NoBundleConductorActivity> testRule = new ActivityTestRule<>(NoBundleConductorActivity.class);

@Before
public void setUp() {
    Activity activity = testRule.getActivity();
    activity.runOnUiThread(() -> {
               router = testRule.getActivity().getRouter();
               router.setRoot(RouterTransaction.with(new NoBundleController()));
           });
}

@Test
public void titleIsDisplayed() {
    onView(withText("Super Awesome Title")).check(matches(isDisplayed()));
    }
}

Or if your controller uses a Bundle in it's contructor as most of our do:

@RunWith(AndroidJUnit4.class)
public class BundleControllerEspressoTest {

private Router router;
private ControllerBundleData controllerData;

@Rule
public ActivityTestRule<BundleConductorActivity> testRule = new ActivityTestRule<>(BundleConductorActivity.class);

@Before
public void setUp() {
    controllerData = new ControllerBundleData();
    Bundle bundle = new Bundle();
    bundle.putSerializable(YOUR_BUNDLE_KEY, controllerData);

    Activity activity = testRule.getActivity();
    activity.runOnUiThread(() -> {
               router = testRule.getActivity().getRouter();
               router.setRoot(RouterTransaction.with(new BundleController(bundle)));
           });
}

@Test
public void titleIsDisplayed() {
    onView(withText("Super Awesome Title")).check(matches(isDisplayed()));
    }
}
like image 116
Kai Avatar answered Sep 27 '22 22:09

Kai