java - Dagger 与二传手进行测试

标签 java android dependency-injection dagger

我真的刚刚开始进行 android 测试,我意识到依赖项很难测试。对于我的前几个测试,我使用 setter 来注入(inject)模拟对象,但在阅读了一些有关 Dagger 的内容后,我正在考虑使用它。下面是我目前进行的一些测试的示例。

在这种情况下,我尝试测试的方法依赖于标记对象。我为那个对象添加了一个二传手。为了测试该方法,我构建了两个不同版本的依赖对象,每个版本都使用不同的标记对象模拟。

正如我所说,我已经阅读了一些有关依赖注入(inject)和 Dagger 的文章,并且我想我了解如何拥有一个用于生产的模块和一个用于测试的覆盖模块,但我开始考虑完成与下面相同的事情使用 Dagger,我需要三个不同的模块。

  1. 生产模块——提供实物
  2. 测试模块 1 - 提供配置为返回的模拟对象 hasAccuracy() = false 和 getAccuracy = null
  3. 测试模块 2 - 提供配置为返回的模拟对象 hasAccuracy() = true 和 getAccruacy = 44.0f

为此我真的需要 3 个不同的模块,还是我遗漏了什么? 将这样的东西转换为使用 Dagger 而不是 setter 有意义吗? 如果是这样,有人可以提供一些关于如何去做的指导吗?

    @Test 
    public void testGetGoogleMapMarkerParametersWithoutAccuracy() {
        when(mockRailsMarker.hasAccuracy()).thenReturn(false);
        when(mockRailsMarker.getAccuracy()).thenReturn(null);
        MapMarker androidMapMarker = new MapMarkerBuilder().withBus(mockBus)
                .withMarker(mockRailsMarker)
                .build();
        assertThat(androidMapMarker.getGoogleMapMarkerParameters().getCircleRadius()).as("radius is zero").isEqualTo(0.0f);

    }

    @Test 
    public void testGetGoogleMapMarkerParametersWithAccuracy() {
        when(mockRailsMarker.hasAccuracy()).thenReturn(true);
        when(mockRailsMarker.getAccuracy()).thenReturn(44.0f);
        MapMarker androidMapMarker = new MapMarkerBuilder().withBus(mockBus)
                .withMarker(mockRailsMarker)
                .build();
        assertThat(androidMapMarker.getGoogleMapMarkerParameters().getCircleRadius()).as("has a valid radius").isEqualTo(44.0f);

    }

最佳答案

我想我自己找到了解决方案。

在我上面的问题中,我正在测试一个方法,该方法依赖于一个名为 RailsMapMarker 的类的实例。我满足该依赖性的方式是创建一个模拟并通过MapMarkerBuild 过程中的 setter 方法。

在这里用 Dagger 做同样的事情是我会做的。我说会,因为事实证明这个特定对象已经可以通过构造函数传入,所以这更像是一个基于我为另一个依赖项所做的事情的示例。

首先,我创建了 2 个模块,一个用于生产,一个用于测试。

生产的看起来像这样(这在你的主项目中)

@Module(injects = MapMarker.class)
public class AFirstDaggerModule {

    @Provides
    RailsMapMarker provideRailsMapMarker() {
        System.out.println("inside dagger -non mock");
        return new RailsMapMarker();

    }

}

和这样的测试(注意@Singleton 注释,这会将相同的实例注入(inject)到测试类和被测类中),这是关键。 (这在你的测试项目中)

@Module(injects = { MapMarker.class, MapMarkerTest.class })
public class AFirstDaggerModule {

    @Provides @Singleton
    RailsMapMarker provideRailsMapMarker() {
        System.out.println("inside dagger - mock");
        return mock(RailsMapMarker.class);

    }

}

在 MapMarker 类和 MapMarkerTest 类中,我都有一个带注释的字段。

map 标记类

@Inject
RailsMapMarker railsMapMarker;

MapMarkerTest 类

@Inject
RailsMapMarker mockRailsMapMarker;

在我的应用程序类中,我有一个用于创建图形的字段和图形的 getter

private static ObjectGraph objectGraph;

public static ObjectGraph getObjectGraph() {
    return objectGraph;
}

在我拥有的应用程序的 onCreate 方法中:

    objectGraph = ObjectGraph.create(new AFirstDaggerModule());

AFirstDaggerModule 是应用程序和测试项目中模块的名称

然后在我正在测试的类的构造函数中 在测试类的 setUp() 方法中我有这个:

    MyApp.getObjectGraph().inject(this);

在我运行测试之后,我在我正在测试的实例中注入(inject)了一个模拟并且我在我的测试类中有一个字段(mockRailsMarker),它是对同一个模拟的引用因为模拟的相同实例被注入(inject)到两个字段中(由于 @Singleton 注释)。

这意味着我的 MapMarker 类中不需要 RailsMapMaker 对象的 setter,因为它现在由 Dagger 注入(inject),而且我可以完全控制来 self 的测试用例的模拟行为。

我知道这对于通常使用 Dagger 和 mocks 的人来说可能是非常基础的,但我为此苦苦挣扎了一段时间,但我从未真正找到一个地方包含所有细节的东西。我发现的大部分内容都假定您知道大部分内容并展示了其中的一 block 拼图。

无论如何,我希望这对其他人有所帮助,否则当这一切都消失时,我至少能够卷土重来并重温我的内存。

关于java - Dagger 与二传手进行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25309123/

相关文章:

java - Java 方法不兼容

javascript - 如何提示从嵌入 map 进入 Google map 导航器页面打开 Google map 路线?

java - 子组件与组件依赖关系

java - 未找到测试运行程序 'JUnit 4' 的测试

java - 是否有基于静态上下文的标准Java依赖注入(inject)API?

java - Java 中字符串和数字的 String.format()

asp.net-mvc - 在 Controller 中使用 IKernel 可以吗?

javascript - 为什么默认的 Yeoman 应用程序模块不需要一个空数组来进行依赖项注入(inject)?

java - 从 web.xml 加载 struts-config.xml

java - 从年月 (yyyy-MM) 到年月 (yyyy-MMMM)