I would like to run a bunch of tests in my Android App.
The thing is: I want to define first a number of tests N, and make my App run that number of times, one after another.
It's a little tricky in Android, because of the Activities lifecycle, but the goal is to start a test (execute the app again) right after when the last one stoped.
Is that possible? I tried reading the Android Developers Testing section, but I'm having some doubts about if what I want is possible with that technique.
Plus, I want to make each test execute with different values for the variables (different inputs), but that's probably even more tricky, so... let's focus in the first problem :)
Any help?? Thanks
It sounds to me what you want is a mechanism to restart your Android application programatically (and gracefully). Many people may say it is impossible, but you can implement the mechanism.
The basic flow is:
(1) finish() your root activity.
(2) In onDestroy() of your root activity, call startActivity(createMainLauncherIntent()).
(3) And the implementation of createMainLauncherIntent() should look like the following.
private Intent createMainLauncherIntent()
{
Intent intent = new Intent();
// To launch this activity as if it started from the launcher.
intent.setClass(this, getClass());
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return intent;
}
(4) Of course, the onDestroy() should have a mechanism to avoid infinite loop of 'restart'.
A sample of base root Activity class:
https://github.com/TakahikoKawasaki/nv-android-base/blob/master/src/main/java/com/neovisionaries/android/app/BaseRootActivity.java
A sample Android application that implements 'restart' mechanism:
https://github.com/TakahikoKawasaki/nv-android-base-sample
You can run any number of test for your app, you just need to specify the valid test runner. By default, the SDK provides a AndroidTestRunner that allows you to run tests for your app inside an emulator.
After that, you can also use another test runner like Robolectric that allows to run tests directly from your IDE.
You can run as may tests as you want with both solutions, there is no need to kill and restart the app between each test. Even though, it would very inefficient and time consuming to do so.
im not sure, but what about a script witch kills your app and start it again with new inputs, which could be stored in preinitialized db?
here a link to how to kill your aplication: Android ADB stop application command like "force-stop" for non rooted device
You can launch app with params using shell command start and parameter -e:
$ adb shell am start -n com.some.package/com.some.package.MainActivity -e key param
Params will come to the onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bundle extras = this.getIntent().getExtras();
if(extras != null){
String key = extras.getString("key");
}
}
To kill app on android you need to have rooted device. Next command will kill app:
$ adb shell ps | grep com.some.package | awk '{print $2}' | xargs adb shell kill
But I'm sure that standard testing methods will works better. So I recommend you carefully read all Android documentation about testing.
Related
I have a question about using ADB.
I know that this command:
adb shell dumpsys activity
can show me all the activities that are currently running on the device.
But I notice that sometimes, the intents appear like this:
Intent { ...some_intent/activity_name.... (has extras) }
I know that extras mean that the activity has been started with some sort of parameters passed to it (I may be wrong here, please correct me if I am).
So my question is, how can I get the extras of the intent/activity through ADB ?
The reason I need this is because I'm trying to launch an apk (that is installed on the phone) through ADB command, something like:
adb shell "su -c 'am start -n com.package.name/.ActivityName'"
That works and bring up the application. The application has a start screen (say we call it HomeActivity) and you have to click a button and make some selections (say SelectionActivity) and it will go to another screen (say ActionActivity). I want to be able to launch the apk and make it go straight to ActionActivity.
The application will crash if I try to launch the ActionActivity with am start command, I'm assuming this is because it requires parameters from the SelectionActivity screen.
This is why I'm trying to see what are the "extras" or parameters that the ActionActivity screen actually gets, so that I can do something like:
adb shell "su -c 'am start -n com.package.name/.ActionActivity -e param1 val1 -e param2 val2'"
Hope my question is clear.
Please correct me if I'm making a mistake somewhere.
Thanks in advance!
If I am understanding correctly, your target is to start the 'action' activity with correct intent but you don't know what kind of parameter information should be included, right?
The dumpsys command won't dump everything you want, so to simply achieve your target, you have 2 options (you should find one device which you can burn your own firmware into it):
Modify the dump method in AMS to print out more information
Modify the ActivityThread class source code to print out the detailed intent information
According to Android docs:
http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html
"When the user leaves a task by pressing the Home button, the current activity is stopped and its task goes into the background. The system retains the state of every activity in the task. If the user later resumes the task by selecting the launcher icon that began the task, the task comes to the foreground and resumes the activity at the top of the stack."
If I understand this correctly, this means:
Activity A as MAIN Activity.
Activity B that gets started in A, through "startActivity" - common, plain intent instance.
I open app for first time, A gets loaded.
I click on button in A and B is openend.
I press home button.
I open app again, for 2nd time, and B is expected to be shown
...right?
I suppose this is the correct behavior to expect...
However, I am not seeing this in my app.
If I hit "Home button" and then resume my app, by pressing the launcher icon, it will start with the main activity - not the one at the top or latest one.
I am coding on a Samsung Galaxy Tab Android 2.2.1 - I have the most common options in the Android manifest - thing is that I handle like 10 different activities with different intent extras - and a Dispatcher class approach - or save each activity state - sounds quite demanding.
I am using Eclipse IDE with ADT version 12; and I found something very interesting:
When I run the app from the Eclipse IDE, with my device connected, I don't see this behavior. The app behaves as stated in the docs.
In fact, I saw this only after I deployed my apk at the Google Play app repository; and downloaded it to test.
My question is, has anybody found the real reason why is this happening?
Is the documentation wrong? or missing something?
Is this a bug on Android?
Another research I have done is:
When I try my app, downloaded from the google play, as APK, if I enter my app for the 2nd time, I get the "main" activity instead of the last one openend. I press home.
After pressing home, I enter application management settings for android, locate my app and click on "force stop".
After doing this, the app behaves as stated in the docs.
Somebody help! :)
This is a bug in android's platform:
http://code.google.com/p/android/issues/detail?id=2373
The workaround is, to place this in the onCreate method of your main Activity:
if (!isTaskRoot())
{
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN))
{
Log.w(LOG_TAG, "Main Activity is not the root. Finishing Main Activity instead of launching.");
finish();
return;
}
}
as extracted from:
How to prevent multiple instances of an activity when it is launched with different intents
...spent 3 days looking out for this.
I'm just going to explain why it fails, and how to reproduce this bug programmatically so you can incorporate this in your test suite:
When you launch an app through Eclipse or Market App, it launches with intent flags: FLAG_ACTIVITY_NEW_TASK.
When launching through the launcher (home), it uses flags: FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_BROUGHT_TO_FRONT | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED, and uses action "MAIN" and category "LAUNCHER".
If you would like to reproduce this in a test case, use these steps:
adb shell am start -f 0x10000000 -n com.testfairy.tests.regression.taskroot/.MainActivity
Then do whatever is needed to get to the other activity. For my purposes, I just placed a button that starts another activity. Then, go back to the launcher (home) with:
adb shell am start -W -c android.intent.category.HOME -a android.intent.action.MAIN
And simulate launching it via the launcher with this:
adb shell am start -a "android.intent.action.MAIN" -c "android.intent.category.LAUNCHER" -f 0x10600000 -n com.testfairy.tests.regression.taskroot/.MainActivity
If you haven't incorporated the isTaskRoot() workaround, this will reproduce the problem. We use this in our automatic testing to make sure this bug never occurs again.
Hope this helps!
The docs are right, the only possible problem I can think of that is causing this is the device you are testing on, if it works as expected on the emulator (which is stock Android) it should work on at least 90% of Androids, its the manufactures fault for this I believe not Android.
is there a simple way to stop a running application using ADB.
Szenario:
Working on App
Have a script which uploads, installs and starts App on change
Problem:
Currently running version gets killed (not shutdown), which make testing cleanup very hard. Option would be to "do cleanup in between", like after a certain time, but I would prefer to do it in the correct location (so like with the OS, as long as the App is still running, so need to save value, as soon as the OS tells me e.g. memory low or calls onDestroy, I want to save stuff)
Chris
I'm not aware of a way to do this. I was hoping there might be a way to send an intent to tell the app to exit using adb shell e.g.
adb shell am start -a [intent] -n [class]
However, I found that somebody asked this question on a Google forum but they haven't got an answer:
http://groups.google.com/group/android-platform/browse_thread/thread/3fd02d01c6c3b41a/56814e518503efd6
I'm developing Activity which works on data passed in Intent in extras.
This Activity is supposed to be launched by other activities in my app.
However, during development/debugging, I launch this Activity directly, and want to simulate extras in Intent (obtained from getIntent) to pass in desired testing params (sort of command-line parameters).
In Eclipse Run configurations, I can just select Launch action, but no additional data.
Is there some way? Or I must hardcode testing params in java, and not forget to comment them out when testing is finished?
I think eclipse is just using something comparable to the am start method to launch an application. You should be able to do this manually via adb and specify extras; then once you have it working from the command line you can put it behind a button using eclipse's extensibility features.
Here's a writeup found during a brief search: http://learnandroid.blogspot.com/2008/01/run-android-application-from-command.html
I think you may want to just write some proper tests for this purpose.
Take a look at this:
Android Testing fundamentals
You could then be running your test during development, which would launch the Activity as you want it.
I'm trying to use Monkey debuggin tool (from adb) to stress test a part of my application.
As Monkey acts in a total random way, I'd like it to concentrate on the part of code that might contain an error I'm looking for (very rare bug, and I don't know how to replicate it).
So, in my Main activity I have 6 buttons, each fires up a new activity. I'd like to set monkey to look only in one of those activities, and every activity accesible from it. I cannot find a reasonable way to do it.
I've tried the
adb shell monkey -p my.package.name -c android.intent.category.MONKEY 1000
and in my manifest file I've put in some activities, that I'm interested in:
<intent-filter>
<category android:name="android.intent.category.MONKEY"/>
</intent-filter>
But it didn't work. Monkey still fires up activities that are not categorized by this tag.
It is crucial for Monkey to work in selected subactivities, because it wastes about 95% of time roaming through my app, outside of subactivities that I actually want to test.
Also I've tried some simple script to launch the desired subactivity, but with no success.
Looking for any help,
cheers,
kajman
I have also had a bit of problems with constraining the monkey with categories. I think it is not intended to work as you assume. How it works then? I have no clear idea, just experimenting with it. The documentation is quite poor.
For your problem you could consider the following approaches
Put your subactivities under one subpackage and permit access to only that subpackage with the -p option
Add some constraints to your code that prevents the navigation inside the app. For example set the onClickListeners to do nothing or disable back button for the activity under test when some specific condition is met.
P.S. You can use adb shell am start in order to start the desired subactivity. Again poor documentation, no example, but the action is the name of the action you have defined inside intent-filter for the activity in your AndroidManifest. Name is the Activity name, for example
adb shell am start -a my.package.app.ACTION1 -n my.package.app/.sub.MyActivity
I know it is bit late but here is more robust way - use code like this:
ActivityManager activityManager;
activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
if(!activityManager.isUserAMonkey()) {
//stuff you want to execute anywhere but monkey test
});