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

Chr*_*sco 6 android unit-testing dependency-injection dagger-2

使用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();
  } 
}
Run Code Online (Sandbox Code Playgroud)

即使您没有明确调用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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

vau*_*oid 9

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();
Run Code Online (Sandbox Code Playgroud)

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

非正式的方式

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

我最喜欢的黑客是简单地扩展哪个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();
Run Code Online (Sandbox Code Playgroud)

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