Freeze android junit test after test execution - android

after each test execution junit goes to the next test. And activity closes automatically after each test execution.
Its OK when I test functions, but NOT OK when I test views. I want to see execution results on the screen before junit will execute next test.
So, I want to make small delay between tests.
There is one way I can do it:
public void testMyView() throws InterruptedException {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// viewOperations...
}
});
Thread.sleep(3000);
}
But I dont like this way because this code is dirty (especially when I have a lot of such tests).
Another way seems much better:
#UiThreadTest
public void testHandleEmptyAlphabetList() throws InterruptedException {
// view operations
Thread.sleep(3000);
}
BUT: It will block UI thread but NOT test thread. I need to block a test thread.
Is there any way to run Thread.sleep(3000); from this code separately in a test thread?
So, what is the best way to make thread delays between tests?
p.s. Please don't recommend me additional test frameworks, I want to solve my problem using embed tools. Thank you.

I suggest ditching this cumbersome way of unit testing and using Robolectric, so your tests run in the JVM and you don't have to deal with all this nasty setup. You'll be pleasantly surprised on how quickly your View testing runs, and that you don't need to run an emulator!

Try to use Robotium for the tests that need a real android running.
solo = new Solo(getInstrumentation(), getActivity());
[...]
if (failure) {
solo.takeScreenshot();
}
This will save a screenshot to your SD card (needs WRITE_EXTERNAL_STORAGE permission)
Or if you prefer not to use another testing framework (though I would recommend you take a look at it), just steal the code that is used there for taking screenshots

Related

Alternative for SystemClock.sleep in Android Espresso

I am writing my test cases for my app however have come into some minor problems. Many of my test cases have SystemClock.Sleep calls in them, in order for the view to load all the data and display it on the screen. However the number of sleeps to do this has increasingly grown causing the time of these tests to be even longer.
Here is an example of one of these tests
#Test
public void testSearch() {
ExtensionForExpresso.signUp();
SystemClock.sleep(17000);
onView(withId(R.id.menu_offer_search)).check(matches(isDisplayed())).perform(click());
SystemClock.sleep(5000);
onView(withId(R.id.menu_search)).check(matches(isDisplayed())).perform(typeText("Pizza"));
SystemClock.sleep(17000);
onView(withId(R.id.searchSectionSeeAllButton)).check(matches(isDisplayed())).perform(click());
SystemClock.sleep(15000);
onView(withId(R.id.searchResultsRecyclerView)).check(matches(isDisplayed())).perform(RecyclerViewActions.actionOnItemAtPosition(1, click()));
}
Is there an alternative to sleep that will wait for view to appear? Or are there any methods or functions I can add in to reduce the amount of SystemClock.sleep calls?
First, try to disable animation on your device/emulator using adb shell or implement the Espresso Idling Resource in your Android project: http://matgom.com/tutorial/2016/02/21/IdlingResource.html
I would recommend you to implement an IdlingResource and Disable the system animations first. The easiest way to disable system animations is this.
There is no need to use the SystemClock.sleep() method. Instead you could implement a custom sleep method like this:
public void waitFor(int seconds) {
seconds = seconds < 0 ? 0 : seconds;
while (--seconds >= 0) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Then you could call it in your test like: waitFor(2); // 2 second wait

App using Mobile Android GNSK crashes when identifyAlbumAsync() is called before audioProcessStart()

I have being upgrading an application to use the new Mobile Android GNSK but I have noticed that using the new MusicID-Stream is a little bit tricky. If the "identifyAlbumAsync" method get executed before the "audioProcessStart" method(since this need to be executed in a different thread), the application just crashes. In the Gracenote Demo application, the "audioProcessStart" method is continuously running so there is no need to synchronize its execution with the "identifyAlbumAsync" method call. Is it the way it is supposed to be used? It will be convenient if the application didn't crashed at least when the methods are not executed in order. Also in our application, we don't want to have the "audioProcessStart" method continuously like it is done in the demo application. We only want to run the "audioProcessStart" method when the user request identification and when the song playing gets identified , we want to stop the audio processing by calling "audioProcessStop". Is there an easy way to do this? Right now, we are getting the Thread where "identifyAlbumAsync" is running to sleep for 2 seconds in order to make sure that the Thread where the "audioProcessStart" method is supposed to run has time to get executed. Thank you in advance for your prompt response
In the upcoming 1.2 release, IGnMusicIdStreamEvents includes a callback that signals audio-processing has started, and an ID can be synced with this, e.g.:
#Override
public void musicIdStreamProcessingStatusEvent( GnMusicIdStreamProcessingStatus status, IGnCancellable canceller ) {
if (GnMusicIdStreamProcessingStatus.kStatusProcessingAudioStarted.compareTo(status) == 0) {
try {
gnMusicIdStream.identifyAlbumAsync();
} catch (GnException e) { }
}
}
Thanks for the feedback, you're right about this issue. Unfortunately right now sleeping is the best solution. But we are adding support for an explicit sync event in an upcoming release, please stay tuned.

Android: CalledFromWrongThreadException from WebView's shouldOverrideUrlLoading

I am developing on a library that is somehow getting a CalledFromWrongThread Exception crash on Samsung Galaxy S1 (api v7 - android 2.1). The code is something like this:
class MyWebViewClient extends WebViewClient {
#Override
public void shouldOverrideUrlLoading(WebView view, String url) {
someListener.addToUiView();
}
}
and of course, the method that is actually throwing the error (which implements a listener callback):
View v;
public void addToUiView(){
v.addView(new TextView(context)); //<-- this line is throwing the error on rare occasions
}
I'm skipping some code in between, but i'm not doing anything weird in other places. Also note: this crash only seems to have been happening a very very small % of the time. (not necessarily conclusive, as not everyone reports their data).
has anyone else come across this?? Is WebCore threading messing things up?
Now I haven't actually tested this but I am going to answer to the best of my knowledge. That said, my instinct is telling me that you are only seeing the error intermittently because web requests from a WebView (browser) happen with varying levels of asynchronicity and probably utilize a thread pool to accomplish this. Basically, sometimes it requests resources in parallel and sometimes it doesn't. Worse yet you might be seeing this error on only a single device because OEMs optimize OS level code (like the WebView internals) based on their preferences and opinions (especially Samsung). Either way the real problem is that you are doing something "UI related" in a place that is definitely not guaranteed to be "UI friendly"... That is, anywhere where you are getting a subsystem callback.
The solution to your problem is much more simpler than the explanation: just use your context (that I am assuming is an Activity)..
Activitys have a built in function called runOnUiThread(Runnable) that will guard the code inside the runnable from running on the wrong thread. Basically, your problem is really common and android has a built-in solution. runOnUiThread will only add overhead if required, in other words if your thread is the UI thread, it will just run the Runnable, if it isn't it uses the correct Handler (the one associated with the UI thread) to run the Runnable.
Here is what it should look like:
View v;
public void addToUiView() {
final Activity activity = (Activity) context;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
v.addView(new TextView(activity));
}
});
}
i coded that up right inside the SO window so my apologies for any egregious errors, I hope that helps, and let me know if you need more info or of this doesn't solve your problem -ck

Why is Robotium slower when perfoming simple UI tasks in comparison with Android native code?

I'm using Robotium to do some simple UI tasks on my unit testing project. I noticed Solo being significantly slower, I dont know why. I'm new to it.
This code is done with Robotium:
solo.clearEditText(editTextLogin);
solo.clearEditText(editTextSenha);
solo.enterText(editTextLogin, "tecnico#mail.com");
solo.enterText(editTextSenha, "12345");
solo.clickOnButton(0);
This is done with native code:
m_Activity.runOnUiThread(new Runnable() {
#Override
public void run() {
editTextLogin.setText("tecnico#mail.com");
editTextSenha.setText("12345");
loginButton.performClick();
}
});
The code performed with Robotium is much slower when compared to the second one. I can figure easily that Robotium is actually mechanically doing all the stuff, while the native code is just setting values to objects, which can explain the difference, but my question best explained would be, when to use Robotium, the way it should be, the way the real performance gain can be achieved.
My apologize for any mistakes.
You should download the source code for robotium and debug through it. You'll see that there's a lot more going on under the hood. For example, here is a little snippet for clickonbutton:
public <T extends TextView> void clickOn(Class<T> viewClass, String nameRegex) {
final Pattern pattern = Pattern.compile(nameRegex);
waiter.waitForText(nameRegex, 0, TIMEOUT, true, true);
ArrayList<T> views = viewFetcher.getCurrentViews(viewClass);
views = RobotiumUtils.removeInvisibleViews(views);
T viewToClick = null;
for(T view : views){
if(pattern.matcher(view.getText().toString()).matches()){
viewToClick = view;
if(viewToClick.isShown())
break;
}
}
if (viewToClick != null) {
clickOnScreen(viewToClick);
} else if (scroller.scroll(Scroller.DOWN)){
clickOn(viewClass, nameRegex);
}else {
for (T view : views) {
Log.d(LOG_TAG, nameRegex + " not found. Have found: " + view.getText());
}
Assert.assertTrue(viewClass.getSimpleName() + " with the text: " + nameRegex + " is not found!", false);
}
}
It calls my attention you are so worried about test performance.
Android UI testing methods are quite complicated and leaves you with a test case that's hard to follow. Robotium is not focused on performance, it's focus in making an API accesible by developers to make their tests easier to write and read.
I wouldn't try to determine what's the most performant way to do a test. I would do it in Robotium, since it's easier to code and afterwards porting to native if necessary.
In my personal case I don't care Robotium making my tests slower. If that's the price I have to pay to avoid using the native UI testing tool, I am cool with that.
If the test takes too much time you can always run in your CI.
Try with different method as my experience of using
solo.clickOnButton("String") and solo.clickOnButton(index) also differ greatly.
as the first one seems to doing a lot of searching.

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;

Categories

Resources