In my app, I have an Activity, which is basically a form for the user to enter data which is then inserted into a database table via a ContentResolver. How do I test this Activity?
My first attempt was to use ActivityInstrumentationTestCase2 which gives me full instrumentation to simulate entering data. However, the underlying ContentProvider is not closed and destroyed between each test, which leaves the database in an unknown state at the beginning of subsequent tests.
My second attempt was to use ActivityUnitTestCase and inject a mock context that can clean up the database for each test. However, this doesn't allow me to enter text or click on buttons in the activity as it is never actually drawn on the test device.
Does anyone have any suggestions about what else I can try?
it seems that what you've been using is intended for library development
You should look at the monkey binary here , which works great for me.
If you're not satisfied with it you could use monkeyRunner which provides more control over the tests you're running.
Edit :
As far as the database testing goes , cant you use the sqlite3 binary for a simple query after each test?
Edit2:
I am thinking of a .sh script that does the following :
Runs monkey for a while - you can specify the number of events for the monkey to send
Invoke sqlite3 with a query that would check the database integrity into a log file (sqlite3 command can take sql query as a second parameter, and you can use ">" to write the output into some file)
Repeat.
There are tons of examples for .sh scripting on the net so you shouldn't have problem with that.
I am assuming you're doing all this in adb shell, but if you're not, make sure to set all your environment variables correctly. Particularly ANDROID_ROOT, ANDROID_ASSETS and ANDROID_DATA should be set to "/system","/system/app" and "/data" accordingly . Also don't forget to "chmod" the .sh file to be executable ( chmod 777 file.sh ).
Another suggestion is to generate and keep track of the monkey random seeds so you can repeat certain inputs that are causing you problems. You can specify a seed with -s parameter.
Related
I'm following the guide to specify exclusions from full backups but running into a crash when I try and test it.
$ adb shell bmgr fullbackup <PACKAGE>
Works fine - files are excluded as expected.
I clear data then run:
$ adb shell bmgr restore <PACKAGE>
The restore works fine but then the next time I try and run the app I'm getting a ClassCastException:
Caused by: java.lang.ClassCastException: android.app.Application cannot be cast to com.domain.app.MyCustomApplicationClass
It appears that for some reason there is an instance of my application but it's not an instance of the custom application class as specified in the manifest.
Running the app a second time works fine and I can verify that all data was correctly restored.
I am testing this on a debug build and would like to try and resolve this error before pushing the latest changes to production.
The usual cause of this is inducing a manual restore "the wrong way." This is very poorly documented, I'm afraid, but there are different ways of invoking "bmgr restore", one of which will cause exactly the problem you describe.
(The problem, specifically, is that full-data backup/restore operations currently require that the app be launched with neither its content providers nor any app-defined Application subclass instantiated; instead, you run with a base-class Application instance. Trying to cast back to your declared subclass throws ClassCastException as you might imagine.)
In the normal course of things, your app is killed following restore. HOWEVER, if you trigger the restore like this:
adb shell bmgr restore PACKAGE
this does not happen. That particular invocation syntax runs a "my app wants to restore its data 'live' right now; do not kill me before or after" code path, the one that you get via BackupManager.requestRestore(). In this code path the app is intentionally not killed following restore. It's an artifact of the time when key/value was the only backup/restore paradigm, and in that paradigm there are no such Application subclass issues etc.
You need to make sure that when you trigger a restore via bmgr, you are using the full syntax:
adb shell bmgr restore TOKEN PACKAGE
This syntax invokes the complete restore-at-install code path, the one that will tear down your app following the restore specifically to avoid trying subsequent execution with a base-class Application.
'TOKEN' is the identifier of the dataset containing the data you wish to restore. If you are using the local debugging transport, then TOKEN is always "1". If you are using cloud backup, then it will be the device's own current backup dataset identifier if there is one, or the ancestral dataset if the device has not generated one itself. You can see these in the output of
adb shell dumpsys backup | egrep 'Current:|Ancestral:'
The dataset's identifying TOKEN is the hex string given there.
Currently I am using UIAutomator to test our application and all UI elements are accessible by UIAutomator.
Usually build APK with additional code to show dialog, indicating successful completion of test-case (i.e. operation invoked by UIAutomator), to inform UIAutomator to proceed with next test-case.
Code which is responsible to show dialog is not committed into repository and maintained as patches and not allowed to be committed in repository.
For this reason, whenever we want to execute UIAutomator tests, we build APK with additional code residing in patches.
My question: Is there any other way to communicate UIAutomator about successful completion of test-case (i.e. application has completed the operation invoked by UIAutomator), without using dialog.
I need this change to execute UIAutomator tests on release-candidate builds.
What I tried: Set constant delay between test-cases invocation.
But I cannot set constant delay between test-cases, as execution time varies based on test-data and device/environment.
I thought of BroadcastReceiver, but I don't know how to register from UIAutomator?
Is there any other mechanism / workaround to achieve this functionality?
I am not sure what you really asks for, but since I am not allowed to comment, you can correct me if I have misunderstood.
You are looking for a way to assert that a testcase has executed and no anomalies been present in your application?
First you need to identify a UiObject. Then you can make use of
UiObject.waitForExists();
Above method will return true when a uiObject matches the query specified on instantiation.
Another solution is to use a runner which can extend UiAutomatorInstrumentationTestRunner, where you build a TestSuite to execute in set order.
If you want the UiAutomator to report status to the Host console, here is a answer from the post below.
Writing to Android UI Automator output console
Instrumentation.sendStatus(..)
Each key / value pair in the Bundle will be written out like this:
INSTRUMENTATION_STATUS: key1=value1
INSTRUMENTATION_STATUS: key2=value2
INSTRUMENTATION_STATUS_CODE: -1
So, your host can get status in any steps you want.
To run system Command like "ping" in android device , we can use Process to execute them.
I have difficulty in accessing that data which is replied by system for systme commands.
how to set that data in proper format? how to access it and store in different type of variables?
You might want to look at Root Tools - they make it dead simple.
Edit: Ofcourse this works also for non-root commands on non-root devices ... look at getShell(boolean wantRoot)
I assume you executed your command by getting the DataOutputStream for the process. The same way, you can get the command's output by getting the DataInputStream for the same process. However, this will show you all the output. You will have to implement separate logic to parse through this output, make some sense of it and further process it. I suggest you first get the DataInputStream and print out the output, so you get a better idea. There is no easy way to do this, except probably the answer from Eugen Rieck.
I am using my Android app to launch a native binary. I would like to display the output of that binary in a small window in my application. How would I go about either displaying the output in a TextView or showing the terminal in a small window (preferred)?
Thanks.
The gist of the article that Alex linked to is that Runtime.exec() returns a Process object, which lets you get the process' standard output (and stderr, too) as Java streams via Process.getOutputStream()/getErrorStream(). Get them, read them in a thread (they do properly block - you don't want to block the UI thread), pass the data back to the UI thread. Much, much better. I rescind my previous answer.
The article also recommends wrapping the stream in a BufferedReader so that you can do readLine.
Here's one scheme. NDK is not necessary for this one.
You create a temporary file in your app's data dir. You run the binary, specifying the same file as an output direction in the command line using Runtime.exec(). The command line you'll have to specify would invoke not the binary itself, but sh, and one of the command line parameters would be a redirection: >myfile.txt.
You then start a worker thread that reads the same file. You'll need to carefully implement new data detection - as this is a file, not a pipe, the reading operation will simply terminate once the end of file is reached; it won't block until new data appears.
Then you pass the data from the worker thread using Activity.runOnUiThread() or Handler.post() to the main thread, where it's used to update TextView's content.
A cleaner way would involve creating a pipe pair with mkfifo() and redirecting output in place using dup2() from a pipe handle to the file handle value 1 (stdout). That's how they normally do it in the C/Linux world. There's probably an Android example out there, I've never done that.
Oh, and before you do all that, make sure the binary does not have a more palatable interface. More often than not, Linux binaries are based on a static/dynamic library where all the yummy functionality is, one that can be linked with and called directly.
EDIT: Especially if it's logcat. There are other ways to read a log in Android.
I am doing some ui automation, and I am able to store screen touches using getevent, but when I try to send this using sendevent, it takes a really long time, making it hard to actually replay the inputs.
I have already trying loading the script onto the device and running the script locally on the device (a script with a bunch of sendevent commands). But this only imporved this slightly. Is there some other way to inject these commands in a quicker way?
The handler for touch is implemented differently across devices. You should cat /proc/bus/input/devices to see where the touch handler is implemented.
You can also do adb shell getevent, interact with the device and see the output for the interface name.
The reason why your replay takes a long time is because the sendevent binary opens the interface file, writes data to it and closes it for every call to sendevent. So in theory, if you have a bunch of sendevent commands, the binary is opening the interface file, writing data and closing it for every command.
The way I've solved this issue is by re-writing the sendevent.c file under /system/core/toolbox to open the file only once during replay, writing all the data and closing it at the end of the replay. It works perfectly for me!
OK.
Instead of using the getevent/sendevent you can try direct reading from the event interface
inside adb shell try:
dd if=/dev/input/event6 of=record1 # to record
dd if=./record1 of=/dev/input/event6 #to play
However, this may run too fast...