views:

800

answers:

3

I'm in the process of working on an automated test suite for our android app, and running into trouble waiting for activities to fully load. I can call getActivity, but just because it shows the activity that I'm hoping to see in my test doesn't always seem to mean that the activity's components are ready for use (fully loaded). Looking through the Activity API didn't turn anything up, and other methods seem too invasive and have spoiled the tests initial state. Does anyone know if there's a way to ask the app or the VM if the current activity is loaded?

A: 

There may be a more elegant way, but did you try setting a boolean at the end of your OnCreate() method?

RickNotFred
After onCreate there is onStart and onResume...
Alex Volovoy
That's more elegant than my current "touch everything touchable/read everything readable" method, but does onCreate really mean that it's been really created? Looking at the process flow for activities, it seems like onResume might even be better. I'll try both of these and see if I still have issues. Thank for quick inspiration! I'll let you all know the results. Until then, if anyone else knows a way to query the ActivityManager (or anything else) for this, please let me know.
Derrick
Don't use onCreate for sure
Alex Volovoy
A: 

If you create a setUp() method like this in your test case extending ActivityInstrumentationTestCase2<MyActivity>

@Override
protected void setUp() throws Exception {
    super.setUp();

    final MyActivity activity = getActivity();

    tv1 = (EditNumber)activity.findViewById(resId1);
    tv2 = (EditNumber)activity.findViewById(resId2);
}

your Activity will be fully operational and the layout loaded, demonstrated in this case by the fact that you can access the Views and its content

@SmallTest
public void testSimpleCreate() {
    final MyActivity activity = getActivity();
    assertNotNull(activity);

    assertNotNull(tv1);
    assertEquals("mystr1", tv1.getText().toString());
    assertNotNull(tv1);
    assertEquals("mystr2", tv2.getText().toString());
}
dtmilano
This suggestion above is the crux of my problem. I can currently query the application for the current activity, but even after the current activity matches the one I'm waiting for, calling findViewById will often fail (seemingly because though the activity is on the top of the activity stack, not all of its views are loaded.) Our immediate solution was to place sleeps in the test code, but this is also fragile since from time to time, our sleep isn't sleepy enough.
Derrick
Though I do see in the logcat log that the ActivityManager chimes in to say that the given activity is now "displayed". I don't know if that means that the activity is now fully loaded and ready to be abused or not though, and I also don't know how to get at that information programmatically. Thank you all for your help with this. Please let me know if I'm missing something from the example laid out above by dtmilano (it wouldn't be the first time!)
Derrick
After `setContentView()`, everything should be accessible in your view hierarchy. I would say the only exception is views that are loaded asynchronously, such as individual rows of a `ListView` being bound to a data source.
Christopher
+1  A: 

As I mentioned in a comment, your view hierarchy should be working after your call to setContentView() early in onCreate(). I've never had any problems like this with any activity or test class..

I'm not sure this is of any help for this specific case, but in general you can determine when the UI event queue is empty by calling getInstrumentation().waitForIdleSync(). That'll block until there's no more UI events to process.

Christopher
I think our problem was with toast elements throwing a wrench into the timing. Your second suggestion is something I'd like to look into further, but it looks like it will require us to extend from the InstrumentationTestCase class. Is there any other way to get instrumentation benefits without extending that you know of?
Derrick
Where were your Toasts being called? What class are you extending at the moment?
Christopher
Our toasts are mostly called from activities through anonymous inner classes implementing an abstract async task class for simple error/success messaging. Our test classes extend from a parent class that imports from junit and hamcrest without extension, and I think we were hoping to leave it unpinned that way. I don't see any other way though to connect to the instrumentation functionality. If there is please let me know. Otherwise, if there's another way to use toast that will keep it from causing this issue, that would be good too. Thanks : )
Derrick
It seems odd that Toasts being called in an async manner would cause any problem. If you're not extending `AndroidTestCase` or `ActivityTestCase`, I'm not sure how you're managing to properly start an `Activity` at all. Could you maybe update your question with a code snippet or something?
Christopher
The Toasts seem to take different amounts of time each time, though that might not be the best way to describe what's happening there. They seem to take focus in unpredictable ways, but I need to read up on them more. Our test setup is a bit different. We have both unit and what we call story tests. Since we didn't want to deploy the story tests with the app, but wanted to be able to perform black box testing of functional flow, we created a way to remote control it with a command setup. It works great, except for this timing issue : ( I'll look at the Instrumentation code for clues.
Derrick
Ah ok, sounds interesting. But you should be able to do black box functional testing by means of a separate Android project, with the same package hierarchy (but different <manifest> package name), using tests that extend InstrumentationTestCase. The "New Android Project" wizard in Eclipse encourages this setup: two separate APKs for app and tests.
Christopher
That's a really interesting point. There was some debate locally about how to implement our "actual" black box testing in which the QA department (Perl) won the day. That was the reason for the remote control setup. They'll telnet into the device (corral of devices) and run the story tests. The dev group is pursuing its own implementation of the story tests at a faster pace than QA to show that the test framework works properly and to be able to sign off on our stories. What a tangled web we weave for ourselves.
Derrick