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!
Related
I am creating a user interface test for an Android app. The test taps a UI element and expects another UI element to appear. The test will only pass if I include a Thread.sleep after tapping the first UI element. How can I avoid this?
Here's the test:
#Test
public void mapInfoIsDisplayed() throws InterruptedException {
// Tap on the crosshair at the centre of the map.
onView(withId(R.id.map_crosshairs)).perform(click());
Thread.sleep(100); // Why is this required?
// Verify that the view is displayed
onView(withId(R.id.feature_title)).check(matches(isCompletelyDisplayed()));
}
The app is written in RxJava, uses Hilt for dependency injection and Espresso as the UI testing framework.
I want the test dependencies to run synchronously on the main thread so my test uses:
the trampoline scheduler for RxJava during tests (executes on the calling thread)
an in-memory Room database which allows queries on the main thread
I have also disabled animations through the emulator settings and have also added the following to my build.gradle (although I'm not sure it does anything):
testOptions {
animationsDisabled = true
}
With all this I would expect the test to run synchronously, waiting for any dependent threads to finish before testing for whether my the new view is displayed. This doesn't appear to be happening so I'm left with a flaky test.
I have a strong suspicion that the production code is being executed asynchronously somewhere, the problem is I can't pinpoint where (it'd be great if there was some way in Android Studio to find this).
How can I ensure all code is executed synchronously, thus avoiding the Thread.sleep?
I don't know if I'm really rusty with JUnit or their is a concept with Android Testing in particular I'm not familiar with but:
I'm finding it very difficult to understand how my tests get run.
I've created a Test Project based on my main project, and created a class which extends ActivityInstrumentationTestCase2<SinglePaneActivity> and in this Test Case I've implemented setUp(), testPort() and tearDown() methods.
When I run the project as a Android JUnit test it all tests correctly.
However, adding another class extending ServiceTestCase<NativeService> with the same setUp(), testStart() and tearDown() methods implemented, the test isn't performed.
Looking through the documentation I can't find anything which states how the tests are run, I'm assuming since their is no specific setup it done via reflection.
Given that as the case however, I don't understand the documentation on TestSuites or why my Service test case isn't running.
Am I the only one that's finding the usually very well written Android Documentation lacking when it comes to testing?
As #Blackbelt says, the was a warning in the Log's indicating that the Test wasn't running.
My problem was that I had used the constructor auto generated for me by eclipse
public NativeServiceTestCase(Class<NativeService> activityClass) {
And the error was output as a warning in LogCat explaining you need to have an empty argument constructor (But that error wasn't repeated anywhere else with any visibility).
I'm trying to write a batched instrumentation test (using ActivityInstrumentationTestCase2) for a particular Activity where I change the intent each time the test runs. I can do this with a single test, and just loop through stopping and restarting the Activity with the new intent, but this is not what I want. One reason is they really should be separate test runs. The other reason is, I'm using Spoon to generate a report when the tests finish, and the report will rightly think I only ran one test.
What I would like is it to treat a single test as a possibly infinite number of tests, and pass the data into the test each time the test runs.
Unfortunately you can't use Theories because it results in a RuntimeException where the InstrumentationTestRunner can't find my tests. Anyone have any luck with this?
You could always just create a "testing" intent. In order to simulate the relaunching of the application, make a method or several methods that reset all your static variables between tests. Then you can test the classes from within a testing intent inside the application itself using
assert("value", MyClass.myMethod);
resetStatics();
assert(true, MyClass,myMethod);
resetStatics();
I don't know how much this will help you, if at all, but this is how I started writing my own tests.
I recently discovered that you can add a public static Test suite() method to a test class, and when you run just this single test class, InstrumentationTestRunner will run the Test returned by this method. This is helpful because suite() can explicitly call any constructor of your TestCase, including one with parameters.
Is there any sense in calling a native function from a separate Java thread, or is it already being run in a separate thread by Dalvik VM?
Native methods are run just like other methods(unless specified otherwise in method description). You should handle the cases where you need to to run code that is slow so that UI wont be blocked. There are multiple ways for this, check this:
http://developer.android.com/resources/articles/painless-threading.html
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