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.
Related
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);
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.
In this thread it's explained how to mock android service:
Is it possible to mock android services under unit tests?
But how can I make my activity use this mock instead of real service?
I'm not using any DI frameworks.
Thanks!
You have to use something, if not DI, just make some Factory class that in test returns a mock instead of real instance.
I'm trying to test a service that requires a real Application object, not the MockApplication that the ServiceTestCase provides.
How can I create a real Application object in my ServiceTestCase?
A service has two inherent dependencies, its Context and its associated Application. The ServiceTestCase framework allows you to inject these dependencies, and thus perform unit tests with controlled dependencies in an isolated environment.
You should not use the real Application in your tests, but if you know what you are doing you can inject it using ServiceTestCase.setApplication().
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.