Dagger vs测试的二传手

时间:2014-08-14 13:23:27

标签: java android dependency-injection dagger

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

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

正如我所说,我已经完成了关于依赖注入和Dagger的一些阅读,我想我知道如何制作一个用于制作的模块和一个用于测试的重要模块,但我开始考虑完成与下面相同的操作有了Dagger,我需要三个不同的模块。

  1. 生产模块 - 提供真实对象
  2. 测试模块1 - 提供配置为返回的模拟对象 hasAccuracy()= false和getAccurracy = null
  3. 测试模块2 - 提供配置为返回的模拟对象 hasAccuracy()= true和getAccruacy = 44.0f
  4. 我真的需要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);
    
        }
    

1 个答案:

答案 0 :(得分:1)

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

在我上面的问题中,我正在测试一个依赖于一个名为RailsMapMarker的类的实例的方法。我满足这种依赖的方式是创建一个mock并通过setter方法“注入”它MapMarkerBuild进程。

与Dagger做同样的事情就是我会做的。我会说,因为事实证明这个特定的对象已经可以通过构造函数传递了,所以这更多的是基于我为另一个依赖所做的事情。

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

制作一个看起来像这样(这在你的主项目中)

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

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

    }

}

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

@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类中,我都有一个带注释的字段。

MapMarker类

@Inject
RailsMapMarker railsMapMarker;

MapMarkerTest类

@Inject
RailsMapMarker mockRailsMapMarker;

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

private static ObjectGraph objectGraph;

public static ObjectGraph getObjectGraph() {
    return objectGraph;
}

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

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

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

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

    MyApp.getObjectGraph().inject(this);

毕竟当我运行测试时,我在我正在测试的实例中有一个注入的模拟我在我的测试类中有一个字段(mockRailsMarker),它是对同一个模拟的引用因为同一个mock实例被注入两个字段(由于@Singleton注释)。

这意味着我不需要在MapMarker类中使用RailsMapMaker对象的setter,因为它现在由Dagger注入,并且我可以完全控制来自我的测试用例的mock的行为。

我知道这对于那些通常使用Dagger和嘲讽的人来说可能是非常基本的,但是我在这方面挣扎了一段时间,而且我从未在一个地方找到任何具有所有细节的东西。我发现的大部分内容都假设你知道大部分内容,并展示了一个难题。

无论如何,我希望这可以帮助别人,否则我会至少能够在这一切消失之后回归并重温我的记忆。