So I've got an Android library that I need to do unit testing on. You pass the library some handlers, and I need to unit test based on the messages sent to those handlers from the library.
The problem is, I don't know how to tell a test to wait until I get a response back. I have a timer checking the response every 10 seconds in my test method and if it sees a response is does an assert, but the test method schedules the timer task and then finishes as successful instead of waiting for an assert in the timer task.
Is there a way to have the test explicitly wait until it runs into an assert before finishing? Or some other way of accomplishing this?
Thanks!
You can create mocks of the handlers. Mocks can/should replace the actual handlers in the unit test of the library. You have full control over mocks, and avoid threading issues (unit testing is damn hard with threading involved).
Related
I had an issue to run my ui test
#Test
fun firstUi() {
onView(withId(R.id.home_profile_tab)).perform(click())
onView(withId(R.id.enter)).perform(click())
onView(withId(R.id.tvCountryCode)).check(matches(withText("+964")))
}
This test run and passed
But the issue is, after running test and reaching to first line, the firs perform(click)) executed after around 90 seconds, and it is almost constant and every time it takes 90 seconds
But after that (90sec) other lines executed and test completed around 4 seconds and passed successfully
Base on android documentation:
Each time your test invokes onView(), Espresso waits to perform the
corresponding UI action or assertion until the following
synchronization conditions are met:
The message queue is empty.
There are no instances of AsyncTask currently executing a task.
All developer-defined idling resources are
idle.
So how and where can I investigate more to detect to root cause of issue???
Or what I'm doing wrong???
With the help of this post I found what was my issue
I live in iran and most of services because on sanctions are banned here
So I looked in Frames, so I found that some AsyncTask are exist for some sdk, that are trying to send request to their server, but because of ban they couldn't
So they keep retrying, maybe after 90sec without a successful request call they give up, and Espresso requirements meet to continue running tests
My Solution was using VPN, so sdk can successfully make request to their servers
I'm using IdlingResource to synchronize a few network related tasks. I register and unregister idlingresource in the #Before and #After methods. The instrumentation is AndroidJUnitRunner.
The basic sequence of steps are:
Espresso clicks a button which makes a network request
When I get response, espresso clicks another button which starts a new activity.
Make more network requests via the new activity.
What actually happens though, is that the first network request is made but new activity is not started. I have a feeling that the main thread is looping somewhere, but I can't pinpoint it.
When I execute a single test (right click method, click on "Run testmethod..") it works, but when I try to execute all the test methods in the class, it fails.
The cool thing is even if every method is empty, save for one which actually does the UI testing, it still fails.
A similar question is in this thread, but has no answers: Espresso 2 on Android, intermediately tests fail after failing to start the activity under test while activities from previous tests are still alive
Any help will be appreciated.
I'm running a test with Robolectric runner. The code under test verifies it's not executed on the main thread:
if (Looper.getMainLooper().getThread() == java.lang.Thread.currentThread()) {
new IllegalStateException("Method called on the UI thread");
}
The Robolectric test raises this exception, and I don't want that. I tried running the code from a Robolectric.getBackgroundScheduler(), but I'm still getting the exception.
How can my test run in a different thread?
The main idea in testing multithreading code is to make it run in controlled way on a single thread.
What I would do:
Move checking code to some class helper
Inject it and mock it under the test
Pluses of this solution:
It will resolve your issue
It will remove duplication and move you closer to SRP (single class responsibility principle)
Minuses:
It requires proper naming since it will hide functionality behind method
It will give you additional flexibility that you might not need
Success!
I have a set of AsyncTasks for which I want to test behavior when completed in different orders. Can I do this with generic Robolectric functionality or do I need to mock a complex asynchronous handling my background jobs?
Simplified I mean something like:
trigger functionality which start taskA and taskB
assert
complete taskA
assert
complete taskB
assert
trigger functionality which start taskA and taskB
assert
complete taskB
assert
complete taskA
assert
Thx
It's hard to test asynchronous code in unit tests. You can consider converting your AsyncTasks into RxJava code. There is a module for Android called RxAndroid. You can also read an article explaining how to Replace AsyncTask and AsyncTaskLoader with rx.Observable – RxJava Android Patterns. When you read section about testability, you can notice that with RxJava you can easily convert non-blocking request into synchronous, blocking request in the following way:
List results = getWeatherForLargeUsCapitals().toBlocking().first();
assertEquals(12, results.size());
After that, your application will use asynchronous code, but your tests will be synchronous and you will be sure that assertions will be executed when request is finished.
I'm not a fan of async tasks. As for me I would suggest to follow Piotr answer. This will make you app cleaner, maintainable and attractive.
If you decide to go with AsyncTask you should extract async task body and completion body to the methods. So in test you can call them in any order that you want. Of course it will require making these methods at least package visible which is not something I would to do. Because changing the code to convince the tests running is evil.
How do you create unit tests for an Android activity that starts async tasks in onCreate? I would like to test the result of these tasks.
It is hard to write tests for a lot of Android functionality, since you can't instantiate classes like Activity outside of Android.
You might be better off doing a true unit test...test the function whose behavior you care about in isolation. Don't try to test it in the context of async task, activity, etc.
You might need to refactor your code a little bit to be able to do that, but its worth it to have testable code!
Running true units tests as mentioned in Cheryl's answer would be ideal. However if you still find yourself wanting to test the result AsyncTasks or any long running asynchronous operation in an Activity Test, Espresso is the silver bullet.
Espresso automatically waits for AyscTasks to complete and the developer can manually tell Espresso to wait for custom background tasks running via the IdlingResource APIs.
Here's a tutorial to help you get started: http://blog.sqisland.com/2015/04/espresso-custom-idling-resource.html
IdlingResource documentation: http://developer.android.com/reference/android/support/test/espresso/IdlingResource.html