5 votes

Le test unitaire de RoboGuice injecte le module de l'application au lieu du module de test.

J'essaie d'écrire un test JUnit pour un service Android en utilisant RoboGuice 2.0. J'ai un module de test qui lie les dépendances injectées aux objets fantaisie de Mockito. Cependant, lorsque je lance le test, les implémentations réelles de mon module d'application sont injectées à la place. Voici une partie du code concerné :

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 et MockSharedPreferences sont des implémentations abstraites vides de IFooManager et SharedPreferences, nécessaires car RoboGuice ne peut pas injecter des objets fantaisie d'interfaces. . J'utilise Mockito avec Dexmaker pour prendre en charge la génération de bytecode pour les classes simulées. De plus, je n'utilise pas Robolectric, j'exécute ces tests sur un appareil ou dans l'émulateur.

Lorsque j'exécute ce test, j'obtiens l'erreur suivante Wanted but not invoked: fooManager.addListener(isA(com.example.IFooListener)) . Après avoir parcouru tout cela avec le débogueur, j'ai découvert que RoboGuice injecte les dépendances de MainModule au lieu de TestModule, donc le test utilise FooManagerImpl au lieu de MockFooManager. Je ne comprends pas comment RoboGuice peut connaître MainModule dans le code de test.

Voici d'autres choses que j'ai essayées pour résoudre ce problème, mais aucune n'a eu d'effet :

  • Spécifiez les modules d'application dans roboguice.xml au lieu d'appeler RoboGuice.setBaseApplicationInjector en MainApplication.onCreate
  • Utilisez Modules.override lors de l'appel RoboGuice.setBaseApplicationInjector au lieu de passer directement la liste des modules.

Comment faire pour que RoboGuice utilise TestModule et ignore MainModule dans mon test unitaire ?

0voto

Suraj C Points 432

Il semble qu'il manque un appel pour faire l'injection dans votre NotificationServiceTest. Cela se fait comme suit :

RoboGuice.getInjector(app).injectMembers(this);

Vous devrez l'ajouter à un moment donné après avoir défini l'injecteur de base et avant l'exécution des tests.

0voto

Noya Points 943

Utilisez

RoboGuice.overrideApplicationInjector(app,RoboGuice.newDefaultRoboModule(app), new TestModule())

au lieu de

RoboGuice.setBaseApplicationInjector(app, RoboGuice.DEFAULT_STAGE, new TestModule());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X