繁体   English   中英

Dagger 2如何在Android上更轻松地进行测试?

[英]How does Dagger 2 make testing easier on Android?

使用DI的最大好处之一是它使测试变得更容易( 什么是依赖注入?也支持它)。 大多数DI框架,我与其他编程语言(工作的MEF.NET, 台风的OBJ-C /斯威夫特Laravel的IoC容器上的PHP,和其他一些),允许开发人员做一个单一的入口点寄存器相关对于每个组件,从而防止“创建”对象本身的依赖。

在我阅读Dagger 2文档之后,整个“无反思”的业务听起来很棒,但我没有看到它如何使测试变得更容易,因为对象仍然在创建自己的依赖项。

例如,在CoffeMaker示例中:

public class CoffeeApp {
  public static void main(String[] args) {

    // THIS LINE
    CoffeeShop coffeeShop = DaggerCoffeeShop.create();

    coffeeShop.maker().brew();
  } 
}

即使你没有明确地调用new ,你仍然需要创建你的依赖。

现在,有关更详细的示例,请转到Android示例 如果你打开DemoActivity类,你会发现onCreate实现是这样的:

@Override 
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
    // Perform injection so that when this call returns all dependencies will be available for use.
   ((DemoApplication) getApplication()).component().inject(this);
}

您可以清楚地看到DI组件与实际代码没有脱钩。 总之,你需要mock / stub ((DemoApplication) getApplication()).component().inject(this); 在测试用例上(如果可能的话)。

到目前为止,我知道Dagger 2很受欢迎,所以我不会看到它。 那么Dagger 2如何让测试课更容易? 我将如何模拟,假设我的活动所依赖的网络服务类? 我希望答案尽可能简单,因为我只对测试感兴趣。

Dagger 2不会使测试更容易

...除了鼓励你首先注入依赖关系之外,这自然会使个别类更容易测试。

最后我听说,Dagger 2团队仍在考虑改进测试支持的潜在方法 - 尽管正在进行任何讨论,但它们似乎并不公开。

那么我该如何测试呢?

你指出想要明确使用Component的类依赖于它是正确的。 所以... 注入依赖! 你必须“手动”注入组件,但这不应该太麻烦。

官方的方式

目前,官方推荐的交换依赖项进行测试的方法是创建一个测试组件,扩展您的生产,然后在必要时使用自定义模块。 像这样的东西:

public class CoffeeApp {
  public static CoffeeShop sCoffeeShop;

  public static void main(String[] args) {
    if (sCoffeeShop == null) {
      sCoffeeShop = DaggerCoffeeShop.create();
    }

    coffeeShop.maker().brew();
  } 
}

// Then, in your test code you inject your test Component.
CoffeeApp.sCoffeeShop = DaggerTestCoffeeShop.create();

这种方法适用于您在运行测试时总是想要替换的内容 - 例如,您希望针对模拟服务器运行的网络代码,或者用于运行Espresso测试的IdlingResource实现。

非正式的方式

不幸的是,它的官方方式可能涉及很多样板代码 - 很好的一次性,但如果你只想换掉一个特定测试集的单个依赖项,真的很痛苦。

我最喜欢的黑客是简单地扩展哪个Module有你想要替换的依赖项,然后覆盖@Provides方法。 像这样:

CoffeeApp.sCoffeeShop = DaggerCoffeeShop.builder()
    .networkModule(new NetworkModule() {
        // Do not add any @Provides or @Scope annotations here or you'll get an error from Dagger at compile time.
        @Override
        public RequestFactory provideRequestFactory() {
          return new MockRequestFactory();
        }
    })
    .build();

请查看此要点以获取完整示例。

“允许开发人员在每个组件的单个入口点上注册依赖项” - Dagger 2中的类似物是ModuleComponent ,您可以在其中定义依赖项。 优点是您不直接在组件中定义依赖项,从而将其解耦,以便稍后在编写单元测试时,您可以使用测试component切换Dagger 2 component

“听起来很棒”整个“没有反思”的事业“ - ”没有反思“的事情并不是关于匕首的”大不了“。 “大不了”是编译时的完整依赖图验证。 其他DI框架没有此功能,如果您无法定义如何满足某些依赖项,您将在运行时迟到时收到错误。 如果错误位于一些很少使用的代码路径中,那么您的程序可能看起来是正确的,但在将来某个时候它会失败。

“即使你没有明确地调用new,你仍然需要创建你的依赖。” - 好吧,你总是要以某种方式启动依赖注入。 其他DI可以“隐藏”/自动化此活动,但最后在某处构建图形。 对于匕首1和2,这是在应用程序启动时完成的。 对于main()中的“普通”应用程序(如示例中所示main() ,对于Android应用程序 - 在Application类中。

“你可以清楚地看到DI组件与实际代码没有脱钩” - 是的,你是100%正确的。 这是因为您不直接控制Android中活动,片段和服务的生命周期,即操作系统为您创建这些对象,并且操作系统不知道您正在使用DI。 您需要手动注入活动,片段和服务。 起初这似乎很尴尬,但在现实生活中唯一的问题是,有时你可能忘记在onCreate()注入你的活动并在运行时获得NPE。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM