Is it possible to write complex functional tests for Android? - android

Is it possible to have something like this? Either with Android/Robotium test frameworks or any other solutions
public void testAll() throws Exception {
test_001_LoginActivity();
test_002_MainActivity();
}
public void test_001_LoginActivity() throws Exception {
startActivity();
test_001_LoginActivity_001_emptyUsername();
test_001_LoginActivity_002_emptyPassword();
test_001_LoginActivity_003_incorrectValues();
test_001_LoginActivity_004_correctValues(); // MainActivity is opened on success
}
public void test_002_MainActivity() throws Exception {
test_002_MainActivity_001_profile();
test_002_MainActivity_002_list();
test_002_MainActivity_003_logout();
}
The idea is to have test_001_LoginActivity() and test_002_MainActivity()contain all the corresponding activity test without recreation of the activities. And to have a result displayed like that:
test_001_LoginActivity() - OK
--->test_001_LoginActivity_001_emptyUsername() - OK
--->test_001_LoginActivity_002_emptyPassword() - OK
--->test_001_LoginActivity_003_incorrectValues() - OK
--->test_001_LoginActivity_004_correctValues() - OK
test_002_MainActivity() - NOK
--->test_002_MainActivity_001_profile() - OK
--->test_002_MainActivity_002_list() - NOK
--->test_002_MainActivity_003_logout() - OK
Which means that all tests for LoginActivity are passed successfully; test_002_MainActivity_002_list() test failed for MainActivity, but test_002_MainActivity_003_logout() test was passed(since activity was not recreated)
I'm new to testing, so maybe I'm getting it wrong and tests are intended to be executed for a brand new activity instance always?

What your are trying to do might be possible if you rename all test_00X_METHOD methods becuase currently it will go to total mess because "test" prefix before a methods has a special meaning for jUnit Framework - beside all will be executed by you from testAll() also all methods will be executed latere seperately as jUnit run all methods with "test" prefix as seperate test case and application is even restarted between those methods. So it should works fine if you throw away all "test" prefixes but keep it for testAll(). And you needn't "startActivity()" method at the begining of test_001_LoginActivity() because Activity is automaticaly started - which activity? Activity you passed as type parameter to this class: http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html.
I hope this answer is useful for you.
Krzysiek,
Bitbar Software Engineer

Related

Android Espresso testing - perform click() times out when startActivity() is called by click handler

I'm just trying to test a submit button at the end of a form.
FormAndroidTest.java:
#Test
public void testSubmitButton() throws Exception {
// Execute
onView(withId(R.id.btnSaveFeedback))
.perform(click());
}
The click() is called, I can see it performed the click in the app, but the call never comes back (until it times out).
I've narrowed it down to being caused by the startActivity call in the click handler:
FormActivity.java:
public void onSubmitClicked(View view) {
...
startActivity(new Intent(this, NextActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME));
...
}
I've traced it down to the call sendUp() call in Espresso's Tap.java failing:
private static Tapper.Status sendSingleTap(...) {
...
DownResultHolder res = MotionEvents.sendDown(uiController, coordinates, precision);
try {
if (!MotionEvents.sendUp(uiController, res.down)) { <-- THIS TIMES OUT
Log.d(TAG, "Injection of up event as part of the click failed. Send cancel event.");
MotionEvents.sendCancel(uiController, res.down);
return Tapper.Status.FAILURE;
...
}
Within that it's the uiController.injectMotionEvent(motionEvent); which loops until the injection has completed, which in this case it never does and times out.
I'm assuming it must have something to do with my threads not settling, but I don't see why or how to resolve it. I've seen a few related threads, but the given answers don't seem to solve my exact problem.
Espresso test stuck/inactive after perform(click()) on button in
ViewAnimator - I've already disabled all animations, and manually trying to manipulate the screen doesn't help.
Android Espresso Test gets stuck at perform(click()); - Same answer of manually swiping given, doesn't help.
Thanks

Java - Android : Thread being called (run) twice

I would like some help regarding Java - Android MultiThreading
While learning to develop my app in a multi-threading way in order to take advantage of the ever-growing multi-core devices market share (most devices are quad core now, some even octo-core), I ran in a situation where my threads are either being calling twice or running twice.
I just don't why and how.
[EDIT 3]
Alright, I narrowed down the issue : I called the AsyncTask from the onResume() method. Although my app did not lost focus (which would mean a call to onPause() then back to onResume() upon return of focus in which case my threads would be run twice) during the tests, I solved the issue by moving away the call to FetchFriendsList to another place.
So far so good, but since in my tests the app did not loose focus or perhaps it did but I could not witness it (!), I think there is another reason behind so I'd say my problem is not entirely solved ... at least for the moment. It does work though. Perhaps I did solve the issue but I do not know how :(
[end of EDIT 3]
I am implementing last Facebook SDK and I am using it to fetch the end-user friends list, which seems to do the work.
Since I am running this operation in an AsyncTask, I am not using request.executeAsync().
Instead I am using request.executeAndWait(). Facebook JavaDoc does state that this method must only be used if I am not in a the Main UI Thread which is my case otherwise I would get a NetworkOnMainThreadException.
Anyway, this is where the weird behavior is happening.
private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>();
public final void fetchFriendsList() {
if (this.session != null && this.session.isOpened()) {
final Request requestUserFriendsList = Request.newMyFriendsRequest(
this.session, new Request.GraphUserListCallback()
public final void onCompleted(final List<GraphUser> users, final Response response) {
if (users != null && users.size() > 0) {
Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
userFriendsList.addAll(users);
}
}
}
);
if (this.asyncFlag)
requestUserFriendsList.executeAsync();
else
requestUserFriendsList.executeAndWait();
}
}
In my case, asyncFlag is set to false because I need to do stuff synchronously in that specific order :
Fetch User Friends List (not on the Main (UI) Thread)
Save friends list on device (separate new thread)
Save friends list on a server (separate new thread)
Following this pattern, the line userFriendsList.addAll(users); is called twice.
In the logcat, the Log.vis showed twice as well, and finally looking with the debugger, the content of the user friends list is made of duplicates.
But that's not all ... step 2 and 3 are indeed two separate threads which are both created and spawned within the same method : public final void asyncSaveFacebookFriendsList().
And guess what, this method is even called twice !
just why ?
At the beginning I was calling the method for step 2 and 3 like this :
[...]
userFriendsList.addAll(users);
asyncSaveFacebookFriendsList(); // it was private before
[...]
This is where the issue started as both line were running twice.
So I thought, alright, I'll call it later like this :
[...]
fetchFriendsList();
asyncSaveFacebookFriendsList(); // it is now public
[...]
But the issue remains still.
If I don't call public final void asyncSaveFacebookFriendsList(), then nothing is run twice.
Why does this issue happen ? Is there something I did not get in Java Threads ?
I do not think this is somehow related to the Facebook SDK because following the same pattern (and doing it also at the same time), I have the same issues when fetching and storing the end-user Twitter friends list.
So I do believe I am doing something wrong. Does someone have any idea in what possible case a thread is called twice ?
Note : all threads are started this way : thread.start(). I am not using any ThreadPool nor the ExecutorService.
In case you need more background context :
Content of AsyncTask : (no need to wonder why Void and Long, I remove the irrelevant code related to it)
private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
protected final Void doInBackground(final Long... params) {
if (params[0] != Long.valueOf(-1)) {
[...]
twitterAPI.fetchUserFriendsList();
publishProgress(1, -1);
}
if (params[1] == Long.valueOf(0)) {
[...]
facebookAPI.fetchFriendsList();
publishProgress(-1, 0);
}
return null;
}
protected final void onProgressUpdate(Integer... flags) {
super.onProgressUpdate(flags);
if (flags[0] != -1)
twitterAPI.asyncSaveFacebookFriendsList();
if (flags[1] == 0)
facebookAPI.asyncSaveFacebookFriendsList();
}
}
As you can see, I start step 2 and 3 in onPublishProgress() which runs on the Main UI Thread. Brefore it was in the doInBackground() method : the issue happens in both cases!
[EDIT]
After further test, it would seem any kind of code is in fact running twice.
I created a simple method called test in which in print a counter. The counter incremente twice as well !
Why you use onProgressUpdate?¿?
onProgressUpdate(Progress...), [...]. This method is used to display any form of progress in the
user interface while the background computation is still executing.
For instance, it can be used to animate a progress bar or show logs in
a text field.
This is used not at the finish of the petition, but when progress increased.
Read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You need to use:
protected void onPostExecute(Long result) {

Android test annotations with Robotium

I'm currently building an app in Android, and using Robotium to do functional tests (By the way, don't use Robotium on anything less that Android 1.6, it is way too buggy).
Some of these tests have a random tendency to fail, mainly Robotium missing a text field, or timing out, not reading text. I am trying to use the #FlakyTest annotation, so they will run two or three times before throwing out a failed test error. However, the annotation is not working, the tests do not re-run after a failure.
Here is how I am using the annotation:
public class ClassName extends ActivityInstrumentationTestCase2<HomeActivity>{
#LargeTest
#FlakyTest(tolerance=3)
public void testMethod(){
//Here I run my roboitium scripts.
}
}
Then I run it from the command line:
adb shell am instrument -w com.jayway.test/android.test.InstrumentationTestRunner
Neither eclipse nor the command line execution of the tests takes into account the flaky test annotation. Does anyone see an error with how I am trying to apply #FlakyTest?
I can't see any issue with your use of the #FlakyTest annotation.
I put together a quick test case to test #FlakyTest and Robotium (v2.2):
public class FlakyTestCase extends ActivityInstrumentationTestCase2<Main> {
private static int count = 0;
private Solo solo;
public FlakyTestCase() {
super("com.stackoverflow.example", Main.class);
}
#Override
public void setUp() throws Exception {
solo = new Solo(getInstrumentation(), getActivity());
}
#LargeTest
#FlakyTest(tolerance=3)
public void testFlaky(){
Log.e("FlakeyTestCase", "Execution Count:" + ++count);
solo.assertCurrentActivity(null,Main.class);
solo.clickOnText("Doesn't Exist");
Log.e("FlakeyTestCase", "Shouldn't make it here");
}
}
LogCat showed the following messages:
Execution Count: 1
Execution Count: 2
Execution Count: 3
So the #FlakyTest annotation was definitely being invoked. The (final) failure of the test was shown as:
junit.framework.AssertionFailedError: The text: Doesn't Exist is not found!
And the message "Shouldn't make it here" was never logged.
So as far as I can see, there is no issue with how you've declared your annotation or any problems with #FlakyTest and Robotium, v2.2 anyway.
Perhaps there is an issue with another part of your test code?
In general, when writing tests for Android (with or without Robotium) you have to be much more careful. You can't just say "is this visible". You need to wrap everything in a "wait for" cycle, so would say "wait for this to be visible". This is particularly a problem when running in the emulators, because sometimes things take long without any good reason. Without the waiting cycles, you will never have a consistent run. We have a few hundred tests and we have never needed to use the FlakyTest annotation.
Robotium missing a text field, or timing out, not reading text means
We have to check clearly if the text or any existed on the screen then only need to perform the actions like
if(solo.searchText("Doesn't Exist", true){
solo.clickOnText("Doesn't Exist");
}
Similar if any components like button or others we can achieve this by above logic.
Add this to your code:
import android.util.Log;

Problems with running Android Activity unit-testing from Eclipse

Im having a problem starting or running any activity unit tests from within eclipse.
Even i start a clean project and make a simple test class it always prints to the console:
[2010-10-05 13:10:24 - testAndroid] Collecting test information
[2010-10-05 13:10:25 - testAndroid] Test run failed: Test run incomplete. Expected 2 tests, received 0
Any ideas ?
Just for testing, I have created a fresh Android project called Demo with a test project called DemoTest
The main activity to test is called Main and I have created a simple testclass MainTest that looks like this:
package net.demo.test;
import android.test.ActivityInstrumentationTestCase2;
import net.demo.Main;
public class MainTest extends ActivityInstrumentationTestCase2<Main>
{
public MainTest()
{
super("net.demo", Main.class);
// TODO Auto-generated constructor stub
}
}
My tests used to run fine before, but suddenly I cant run any of them, they all fail with the same error, even I create new a project. It seems like it something to do with Eclipse or and not with the Code.
Update:
Seems like extending SingleLaunchActivityTestCase<Main> is working, but still got no clue about how to make ActivityInstrumentationTestCase2<Main> working.
I had no regression problems. I just couldn't get the example to work. I finally fixed it by defining two constructors:
public MainActivityTest(String pkg, Class<MainActivity> activityClass) {
super("com.myapp", MainActivity.class);
}
public MainActivityTest() {
super("com.myapp", MainActivity.class);
}
It turned out that most emulators before 2.3.3 were silently swallowing the error generated when construction went wrong.
You must put at least 2 methods (i.e 2 test cases) into the Test class. even methods without definition inside can do the trick

Error calling method on NPObject! in Android 2.2

I'm using addJavascriptInterface within my Android application to allow JavaScript to invoke functions I've created in my native Java application.
This worked well in Android 2.1, however in Android 2.2 I receive the error message "Error calling method on NPObject!"
When I instrument the method call the internals of the native method are getting called, however the exception is being throw in JavaScript.
I was getting this exact error:
Uncaught Error: Error calling method on NPObject!
Turns out I was attempting to invoke a JavascriptInterface function from a webview like so:
AndroidJS.populateField(field);
and on the Java side, the function didn't accept a parameter:
public void populateField() {}
Simply allowing the Java function to accept a parameter solved this error for me.
E.g.,
public void populateField(String field) {}
This may not be, and probably is not, the only reason this error could be thrown. This is simply how I resolved my specific scenario. Hope this helps! :)
OK, I have same problem as well, just in today.
What I did is putting code in UI Thread, like code below :
/**
* 給網頁Javascript呼叫的method
* Method for Javascript in HTML
* #param java.lang.String - Playlist ID
*/
public int callListByPID(final String pId)
{
Log.i(Constants.TAG, "PAD Playlist ID from HTML: "+pId);
runOnUiThread(new Runnable()
{
public void run()
{
// Put your code here...
}
});
return 1;
}
This solved my problem, and hope it can help some body... :-)
In my experience this problem is caused by Javascript interfaces bringing back objects that Javascript doesn't automatically identify.
In Android this is caused by wrappers like Boolean or Long in comparison to their native versions boolean and long.
//This will fail
public Long getmyLongVal() {
return 123456789;
}
//This will work
public long getMyNativeLongVal() {
return 123456789;
}
So remove your wrapper classes to any methods being used by Javascript if you want to avoid NPObject errors.
Here's a twist I found on this problem that could be useful for some of the folks running into this problem (and it likely explains intermittent failures that seem to defy explanation)...
If any exceptions are thrown (and not caught) in the return handler code prior to allowing the javascript interface callback to return clean, it will propagate back as a failed call and you will also get this error - and it would have nothing to do with missing functions or parameters.
The easiest way to find this case (whether or not you use this in your final implementation) is to push whatever handler code you have back onto the UI thread (the callback will not be on the UI thread) - this will allow the callback to return clean and any subsequent exceptions that occur will propagate properly up until you catch them or until the app crashes. Either way you will see exactly what is really happening. Otherwise the uncaught exception passes back to javascript where it will not be handled or reported in any way (unless you specifically built error trapping code into the JS you were executing).
Good Luck All.
bh
I had the same problem with Javascript-to-Java interface (WebView.addJavascriptInterface).
In Android 2.1 everything worked just fine but in Android 2.2 Javascript failed to call methods from this interface. It returned an error: Uncaught Error: Error calling method on NPObject!
It seems that on Android 2.2, the WebView has problem with Boolean data type returned from interface functions.
Changing:
public Boolean test_func() { return true; }
... to:
public int test_func() { return 1; }
... solved the problem.
This I believe is no longer supported anymore ( Always game NPObject error ) .
Please refer to the answer in this thread
Visit open an activity from a CordovaPlugin

Categories

Resources