Synopsis
Recently I was testing some single-threaded (non user-interface) Android code that was using a BroadcastReceiver to monitor network state. This post describes how your test can run into thread issues even though your code is not multithreaded.
Introduction
The Android testing framework allows you to test different components of your application on an actual device or an emulator. This framework is great for integration- and functional testing, i.e. testing a combination of modules/classes and interaction with the device and Android components. (The Android testing framework is however not very suitable for unit testing - see my previous post).
When running integration tests with the Android testing framework it is good to keep in mind that by default, tests are not run on the main application thread (also known as the UI Thread). Some Android components such as those that interact with the GUI (i.e. Views) however need run on the main thread. The Activity instrumentation test provides nice support for testing GUI components on the main thread as described in the activity testing tutorial. There are however other components that also run on the main thread and if you do not consider this in your integration tests you might be up for a surprise.
Multithreaded surprise
A good example of a component that runs on the main application thread is the onReceive method of a BroadcastReceiver. As stated in the documentation, "This method is always called within the main thread of its process, unless you explicitly asked for it to be scheduled on a different thread ...".
Recently I was testing a module that is doing some networking related stuff. This module does not spawn off any local threads but it registers a BroadcastReceiver for monitoring connectivity and the state of the wifi interface. When I was testing my code, I occasionally saw some weird sequences of action which were being caused by different threads running in parallel on my module. The reason was that events that arrive on the BroadcastReceiver were being run on the main application thread while the methods invoked from the test were running on a different thread.
Since I do not want to make my code thread safe just for testing purposes I needed to figure out how to run the tests on the main thread. Also, since my code is part of a library and not tied to a particular Android Activity it was not reasonable to use the Activity test case mentioned above.
Test example
The test case below shows the test threading issue in practice with a simple example. All it does is register a BroadcastReceiver that monitors changes in wifi state.
When running this test (with wifi turned on) I see the following logcat output
D/TestStuff(11890): Test is running on thread: Instr: android.test.InstrumentationTestRunner
D/TestStuff(11890): onReceive is running on thread: main
Obviously the testStuff method and the onReceive method are running in different threads. So how can we make the test to run on the main thread, just like the broadcast receiver?
The solution is to use the @UiThreadTest annotation which causes the test to run on the main thread. This annotation does however only have the desired effect if the test case is subclassed from InstrumentationTestCase.
After running the new test we see the following logcat output.
D/TestStuff(12042): Test is running on thread: main
D/TestStuff(12042): onReceive is running on thread: main
Now both the test and the broadcast receiver are running on the same thread.
Recently I was testing some single-threaded (non user-interface) Android code that was using a BroadcastReceiver to monitor network state. This post describes how your test can run into thread issues even though your code is not multithreaded.
Introduction
The Android testing framework allows you to test different components of your application on an actual device or an emulator. This framework is great for integration- and functional testing, i.e. testing a combination of modules/classes and interaction with the device and Android components. (The Android testing framework is however not very suitable for unit testing - see my previous post).
When running integration tests with the Android testing framework it is good to keep in mind that by default, tests are not run on the main application thread (also known as the UI Thread). Some Android components such as those that interact with the GUI (i.e. Views) however need run on the main thread. The Activity instrumentation test provides nice support for testing GUI components on the main thread as described in the activity testing tutorial. There are however other components that also run on the main thread and if you do not consider this in your integration tests you might be up for a surprise.
Multithreaded surprise
A good example of a component that runs on the main application thread is the onReceive method of a BroadcastReceiver. As stated in the documentation, "This method is always called within the main thread of its process, unless you explicitly asked for it to be scheduled on a different thread ...".
Recently I was testing a module that is doing some networking related stuff. This module does not spawn off any local threads but it registers a BroadcastReceiver for monitoring connectivity and the state of the wifi interface. When I was testing my code, I occasionally saw some weird sequences of action which were being caused by different threads running in parallel on my module. The reason was that events that arrive on the BroadcastReceiver were being run on the main application thread while the methods invoked from the test were running on a different thread.
Since I do not want to make my code thread safe just for testing purposes I needed to figure out how to run the tests on the main thread. Also, since my code is part of a library and not tied to a particular Android Activity it was not reasonable to use the Activity test case mentioned above.
Test example
The test case below shows the test threading issue in practice with a simple example. All it does is register a BroadcastReceiver that monitors changes in wifi state.
When running this test (with wifi turned on) I see the following logcat output
D/TestStuff(11890): Test is running on thread: Instr: android.test.InstrumentationTestRunner
D/TestStuff(11890): onReceive is running on thread: main
The solution is to use the @UiThreadTest annotation which causes the test to run on the main thread. This annotation does however only have the desired effect if the test case is subclassed from InstrumentationTestCase.
After running the new test we see the following logcat output.
D/TestStuff(12042): Test is running on thread: main
D/TestStuff(12042): onReceive is running on thread: main
Now both the test and the broadcast receiver are running on the same thread.