Próbuję napisać test JUnit dla usługi Android za pomocą RoboGuice 2.0. Mam moduł testowy, który łączy wstrzyknięte zależności z fałszywymi obiektami Mockito. Jednak po uruchomieniu testu zamiast tego zostaną wprowadzone prawdziwe implementacje z mojego modułu aplikacji. Oto niektóre z odpowiednim kodem:Moduł testowy modułu RoboGuice do wstrzykiwania zamiast modułu testowego
MainApplication.java:
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
RoboGuice.setBaseApplicationInjector(this, RoboGuice.DEFAULT_STAGE,
RoboGuice.newDefaultRoboModule(this), new MainModule());
startService(new Intent(this, NotificationService.class));
}
}
MainModule.java:
public class MainModule extends AbstractModule {
@Override
protected void configure() {
bind(IFooManager.class).to(FooManagerImpl.class).in(Scopes.SINGLETON);
}
}
NotificationService.java:
public class NotificationService extends RoboService {
@Inject
private NotificationManager notificationManager;
@Inject
private SharedPreferences prefs;
@Inject
private IFooManager fooManager;
private IFooListener listener = new FooListener();
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
fooManager.addListener(listener);
}
@Override
public void onDestroy() {
super.onDestroy();
fooManager.removeListener(listener);
}
private class FooListener implements IFooListener {
// Do stuff that fires Notifications
}
}
NotificationServiceTest.java:
public class NotificationServiceTest extends ServiceTestCase<NotificationService> {
@Mock
private MockFooManager fooManager;
@Mock
private MockSharedPreferences prefs;
public NotificationServiceTest() {
super(NotificationService.class);
}
public void testStart() {
startService(null);
verify(fooManager).addListener(isA(IFooListener.class));
}
public void testStop() {
shutdownService();
verify(fooManager).removeListener(isA(IFooListener.class));
}
@Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
Application app = new MockApplication();
setApplication(app);
RoboGuice.setBaseApplicationInjector(app, RoboGuice.DEFAULT_STAGE, new TestModule());
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
RoboGuice.util.reset();
}
private class TestModule extends AbstractModule {
@Override
protected void configure() {
bind(Context.class).toInstance(getContext());
bind(IFooManager.class).toInstance(fooManager);
bind(SharedPreferences.class).toInstance(prefs);
}
}
}
MockFooManager i MockSharedPreferences to puste abstrakcyjne implementacje IFooManagera i SharedPreferences, potrzebne z powodu RoboGuice can't inject mocks of interfaces. Używam Mockito z Dexmaker do wspierania generowania kodu bajtowego dla wyśmiewanych klas. Ponadto, nie używam Robolectric, uruchamiam te testy na urządzeniu lub emulatorze.
Po uruchomieniu tego testu pojawia się błąd Wanted but not invoked: fooManager.addListener(isA(com.example.IFooListener))
. Po przejściu przez to z debuggerem, stwierdziłem, że RoboGuice wstrzykuje zależności z MainModule zamiast z TestModule, więc test używa FooManagerImpl zamiast MockFooManagera. Nie rozumiem, jak RoboGuice wie o MainModule w kodzie testowym.
Oto kilka innych rzeczy, próbowałem to naprawić, ale żaden nie miał żadnego wpływu:
- Określanie modułów aplikacji w
roboguice.xml
zamiast dzwonićRoboGuice.setBaseApplicationInjector
wMainApplication.onCreate
- Zastosowanie
Modules.override
DzwoniącRoboGuice.setBaseApplicationInjector
zamiast tylko przejazdem bezpośrednio na liście modułów.
Co zrobić, aby RoboGuice używał modułu testowego i ignorował moduł główny w moim teście urządzenia?