Use Robolectric to test BluetoothAdapter in android 4.3 - android

In my android app, there the following code:
BluetoothManager bm = (BluetoothManager)activity.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter ba = bm.getAdapter();
I want to do Unit Tests using Robolectric. I am using Robolectric 2.2.
But I found that bm is null, and I don't know how to mock it.

The challenge
The challenge with testing for bluetooth and other system services is that these classes are all final.
The hard way (skip and go to powermock solution if you like)
So if you want to inject anything else you need to make a wrapper around the final class and then provide an implementation forwarding to actual bluetooth classes and an alternative one that mocks your stuff. But then all coded needs to be updated to use that wrapper instead of the final classes directly.
PowerMock solution
PowerMock however should be able to handle these final classes. The summary (follow link for more detail)
Use the #RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
Use the #PrepareForTest(ClassWithFinal.class) annotation at the class-level of the test case.
Use PowerMock.createMock(ClassWithFinal.class) to create a mock object for all methods of this class (let's call it mockObject).
Use PowerMock.replay(mockObject) to change the mock object to replay mode.
Use PowerMock.verify(mockObject) to change the mock object to verify mode.

Related

Mockito when starts actual method call Android UI Testing

We have a Configuration class and LocalStorage class Configuration takes LocalStorage instance in constructor, LocalStorage takes Context in constructor. We are just trying to start with UI testing.
We are trying to do this
private val localStorage = Mockito.mock(LocalStorage::class.java)
// in our setup method
Mockito.`when`(localStorage.getString(anyString())).thenReturn(str)
Here problem is that getString() method call starts happening immediately when tests are run. We have not even written actual test yet.
Mockito Android version: 3.1.0
I think what problem is may be in Mock final Kotlin classes during UI tests. It is looks like what you use plugin for Mockito to "open" classes.
Possible solutions:
Make LocalStorage to be interface, not class. (5th principle of SOLID, abstraction/realisation). Your problem may disappear because interfaces are open by their nature.
Use Mockk library to mock your LocalStorage and other classes. This framework is better for Kotlin.
Have you considered using alternative approach?
doReturn(str).when(localStorage).getString(anyString())
(import needed: import org.mockito.Mockito.doReturn)
Problem was this LocalStorage was being initialized by our Application class. Mock fails when a dependency is already initialized before. Solution is to create a TestApplication with CustomAndroidJUnitRunner. Make sure dependencies are not pre-initialised and only initialise dependencies as per respective test's requirenment.

How can I write unit tests for classes using LocalBroadcastManager?

Our normal way of writing unit tests is using mocks via Mockito. However, LocalBroadcastManager, for some unexplicable reason, is final - thus preventing Mockito from expanding it, which prevents us to mock/spy it...
--> How can I write unit tests for a class that contain LocalBroadcastManager?
I would for example like to check that when some conditions occur etc. certain broadcasts (containing specific extras) are sent out.
Use PowerMock:
Run your test class with PowerMock:
#RunWith(PowerMockRunner.class)
#PrepareForTest({LocalBroadcastManager.class})
Then where-ever in your test you want to mock the static method, do this:
PowerMockito.mockStatic(LocalBroadcastManager.class);
LocalBroadcastManager instance = mock(LocalBroadcastManager.class);
PowerMockito.when(LocalBroadcastManager.getInstance(context)).thenReturn(instance);

Android Unit test API calls with Retrofit2

I haven't done any testing in Android, so please bear with me if this seems a stupid question.
I'm developing an app which makes a lot of network calls from a restful API service. To make the network calls, I'm using Retrofit2 and RxJava.
What would be the best practice/framework to just test if these calls are working? I've started to read the Google Codelab for testing which uses Junit4 and Mockito, but I don't want to do any clicking in the UI to start a test currently, just checking for different API versions which calls are supported or not.
Here some steps for you that I am using:
Use mockito & junit4, for sure :)
I avoid UI tests for these cases
Pass your retrofit Api as a parameter to a class that you want to test
In the test create a mock retrofit api, pass this one as a parameter so you can choose what you want your "Api" to return e.g. objects or errors (see Mockito.when())
Use RxJava's TestSubscriber to test a method e.g. Observable<Location> getLocationFromApi()
Avoid threading in your testing class (e.g. like .observeOn(mainThread())). If inevitable use awaitTerminalEvents in TestSubscriber. If there is no terminal even rethink your test
General tips:
Try to modularize your code so each class has few functionality -> easier to test.
Be patient and don't expect to write tests for e.g. 5% of your code in just one week :) It's a slow process regardless team size

Android unit test/test.runner - access to Application object

I'm using the android.test.runner library and the AndroidTestCase etc. to create some unit tests. I'm finding it useful, but one test requires access to the application object. Usually I just get that from the activity context, e.g.
AppState appState = ((AppState) myActivity.getApplicationContext());
However, the unit tests are in a class which extends AndroidTextCase, and as far as I can see there is no getApplicationContext available. There is a getContext, but I'm not clear if that's what I want. What's the best course of action?
Are you testing your AppState object, or trying to test something else which relies on it?
If you are not testing AppState in this instance can you use a tool such as Mockito to mock up an AppState object for the purposes of your test.

Instrumentation class in the Android API

I have question on the Android API. Android API provides a class called "Instrumentation" class. What is the use of this class? Is the Instrumentation class be used only together with Junit for unit testing.
Can Junit framework can be used to test the methods of the Android API without using the Instrumentation class.
Since Junit package has been included in the Android package, I hope we dont need to use install separately for unit testing.
I would appreciate if you could provide me the information as i can't find these clear information anywhere on the Web.
If we use Junit test framework to test the Android API, can we have test results in the UI format rather than test format.?
Thanks a lot. Apprecite your time.
Regards,
Riyas
The Instrumentation class allows the test case to subscribe to various application events (keypresses, etc), and also programmatically control the UI to enable functional testing of your application.
Therefore, you technically do not need the Instrumentation class for Junit testing if all you are doing is unit testing, and not functional testing of the UI. You could just extend TestCase which does not provide any Instrumentation support.
Here is a link with some fairly good descriptions of the various test classes.
Junit is included within Android and will not need to be installed separately.
Instrumentation API is basically used to inject various kinds of events to the UI so that the application can be stress-tested. You can create an arbitrary event like tapping on the screen and inject it using instrumentation API which is basically like a pseudo event generation.
Instrumentation class is a base class for test frameworks, this provides a very specific functionality, It also provides API to invoke test on device/emulator using ActivityManager Interface via ADB. Also, it can gets back the results to the development machines.
By overriding this class you can enjoy all the context and helper classes you need to run your tests.
Below is a sample implementation, I wrote to explain you the functionality.
public class SampleInstrumentation extends Instrumentation {
#Override
public void onCreate(Bundle arguments) {
super.onCreate(arguments);
Bundle bundle = new Bundle();
bundle.putString("whatisthis","thisiswhat");
finish(0,bundle);
}
}
Manifest:
...
...
</application>
<instrumentation
android:name=".SampleInstrumentation"
android:targetPackage="com.commons"></instrumentation>
</manifest>
Now if you run this command from your development machine.
adb shell am instrument -w -m com.commons/com.commons.SampleInstrumentation
Your instrumentation class onCreate methods get called and you will get some binary encoded response on your console containing data from the bundle you passed to the 'finish' function.
"
whatisthis
thisiswhat
I hope this will make you understand the functionality specific to this base class. For the sake of some motivation, I would like to add that the new android testing framework androidx.test gets compiled with our app (not part of OS and can be modified) directly extends the Instrumentation class (part of Android Framework/OS implementation). Hence you can write your own implementation of a whole new testing framework just by using this class.

Categories

Resources