I am attempting to test-drive a suite of changes I'm making to my Android service (android.app.Service
) - I am using Dagger and Robolectric and I need to replace the field injected classes within the service with some mocks to reduce the test scope...make it (slightly) more 'unit' like.
I inject Providers.of
(Guice syntax there...) into my android.app.Service
. How do I replace them with MockProviders during a unit test?
This is what the relevant service code looks like;
@Inject SpotService spotService;
@Inject Provider<SynchroniseTidePosition> syncTidePosition;
@Inject Provider<SynchroniseSwellDataTask> syncBuoyData;
@Inject Provider<SynchroniseConditionsTask> syncConditionsData;
@Inject SpotRatingCalculator spotRatingCalculator;
@Inject LocalBroadcastManager localBroadcastManager;
@Inject NotificationManager notificationManager;
/**
* @see android.app.Service#onCreate()
*/
@Override
public void onCreate() {
super.onCreate();
inject(this);
...
So, under normal operation the startService(intent)
call lets the service inject it's dependencies during onCreate
and we're all good.
Under my test I want to replace the injected Provider
s get()
calls with Mockito mocks. I have attempted to follow the Dagger test example and created a test module that looks like this;
@Module(includes = OceanLifeModule.class,
injects = {TestSynchronisationServiceNotifications.class},
overrides = true)
static class TestSynchronisationServiceNotificationsModule {
@Provides LocalBroadcastManager provideLocalBroadcastManager() {
return LocalBroadcastManager.getInstance(Robolectric.application);
}
@Provides NotificationManager providesNotificationManager() {
return (NotificationManager) Robolectric.application.getSystemService(Context.NOTIFICATION_SERVICE);
}
@Provides SpotService provideSpotService() {
return mock(SpotService.class);
}
@Provides SpotRatingCalculator provideSpotRatingCalculator() {
return mock(SpotRatingCalculator.class);
}
@Provides SynchroniseTidePosition provideSyncTidePosition() {
return mock(SynchroniseTidePosition.class);
}
@Provides SynchroniseConditionsTask provideSyncConditionsTask() {
return mock(SynchroniseConditionsTask.class);
}
@Provides SynchroniseSwellDataTask provideSyncSwellDataTask() {
return mock(SynchroniseSwellDataTask.class);
}
}
I am expecting that when my actual Service code calls the Provider get()
I would be getting the Mockito mocks back (those are the mocks that my test module @Provides).
This isn't happening. What's wrong with the approach I'm heading down here?
Mockito @InjectMocks annotations allow us to inject mocked dependencies in the annotated class mocked object. This is useful when we have external dependencies in the class we want to mock. We can specify the mock objects to be injected using @Mock or @Spy annotations.
@InjectMocks is the Mockito Annotation. It allows you to mark a field on which an injection is to be performed. Injection allows you to, Enable shorthand mock and spy injections.
We can use Mockito class mock() method to create a mock object of a given class or interface. This is the simplest way to mock an object. We are using JUnit 5 to write test cases in conjunction with Mockito to mock objects.
A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.
Make your own Providers.of()
:
public static <T> Provider<T> of(final T t) {
return new Provider<T>() {
public T get() {
return t;
}
}
}
Dagger should probably include this in a testing module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With