【问题标题】:Replacing Provider injections with Mockito mocks during test with Dagger在使用 Dagger 进行测试期间用 Mockito 模拟替换 Provider 注入
【发布时间】:2013-07-31 22:55:21
【问题描述】:

我正在尝试测试我对我的 Android 服务 (android.app.Service) 所做的一系列更改 - 我正在使用 Dagger 和 Robolectric,我需要用一些模拟替换服务中的字段注入类以缩小测试范围...使其(稍微)更像“单元”。

那么,简短的版本...

我将Providers.of(那里的Guice语法...)注入我的android.app.Service。如何在单元测试期间将它们替换为 MockProviders?

更长的版本...

这是相关服务代码的样子;

@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);
...

所以,在正常操作下,startService(intent) 调用让服务在onCreate 期间注入它的依赖项,我们都很好。

在我的测试中,我想用 Mockito 模拟替换注入的 Providers get() 调用。我尝试关注Dagger test example 并创建了一个看起来像这样的测试模块;

@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);
    }
  }

我希望当我的实际服务代码调用 Provider get() 时,我会得到 Mockito 模拟(这些是我的测试模块 @Provides 的模拟)。

这不会发生。我这里的方法有什么问题?

【问题讨论】:

  • 你能分享一下你的 inject() 方法吗?
  • 嗨,尤金。注入方法位于我的Application 子类下,并遵循熟悉的模式; public static void injection(final T instance) { objectGraph.inject(instance) } 我可以确认“简单”注入(本例中为 SpotService)的实现已被 Mockito 模拟覆盖。只是供应商把我难住了。
  • 有趣。因为在我的项目中,我必须明确地将 Module 注入应用程序。我不知道至少对于“简单”注射可以自动完成
  • 在您在 setUp 中进行注入以进行测试后,Robolectric 会调用 onCreate 吗?
  • 我已经控制了实现“ServiceController”的服务设置,它具有与 Robolectric.buildActivity 方法类似的 API。因此,除了(希望)稍后当我检查生成的通知时,robolectric 并没有直接在这里被利用。这是完整的测试:pastebin.com/535u1PBC

标签: android android-testing dagger


【解决方案1】:

制作你自己的Providers.of():

public static <T> Provider<T> of(final T t) {
  return new Provider<T>() {
    public T get() {
      return t;
     }
  }
}

Dagger 可能应该将它包含在测试模块中。

【讨论】:

  • 感谢您花时间回答杰西。从我上面与 Eugen 的讨论中,很明显我的测试模块工作正常。但是,这是我的服务 inject 方法使事情出错。直到在我的应用程序代码下调用 inject 之前,模拟仍然很强大。注入后,模拟被替换为真实的东西。在所描述的服务下构建的模块图的范围(?)似乎不正确?您对如何避免这种情况有什么建议吗? (即主应用程序注入方法“胜过”测试模块)
猜你喜欢
  • 2017-01-29
  • 2021-05-28
  • 2014-04-16
  • 2011-05-13
  • 1970-01-01
  • 2014-06-07
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多