Dagger2不会在Test

时间:2017-04-21 14:35:24

标签: robolectric dagger-2

根据Dagger 2文档

我正在尝试根据Dagger2's documentation

设置测试环境

(仅针对上下文,我已在Dagger 1中成功完成此操作。)

问题,特别是,虽然Dagger2正确生成DaggerRoboDaggerComponent(在App.java中使用),但它不会生成DaggerTestRoboDaggerComponent(在MainActivityTest.java中使用)。我检查了目录结构,以确保它没有隐藏在一些不起眼的地方,并完成必要的清理,重建,无效缓存/重启等等。

如果有人可以请让我知道我的方式的错误,我会很感激。提前谢谢。

你可以clone the project here

或者,浏览下面的项目文件:

的build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "xx.robodagger"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.google.dagger:dagger:2.10'
    annotationProcessor "com.google.dagger:dagger-compiler:2.10"
    testCompile 'junit:junit:4.12'
    testCompile "org.robolectric:robolectric:3.3.1"
}

App.java

package xx.robodagger;

import android.app.Application;

public class App extends Application {

    static RoboDaggerComponent roboDaggerComponent;
    static RoboDaggerComponent getComponent() {
        return roboDaggerComponent;
    }

    @Override public void onCreate() {
        super.onCreate();
        roboDaggerComponent = DaggerRoboDaggerComponent.builder()
            .roboDaggerModule(new RoboDaggerModule())
            .build();
    }

}

Foo.java

package xx.robodagger;

class Foo {
    @Override public String toString() {
        return "foo";
   }
}

MainActivity.java

package xx.robodagger;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import javax.inject.Inject;

public class MainActivity extends AppCompatActivity {

    @Inject Foo foo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        App.getComponent().inject(this);
        setContentView(R.layout.activity_main);

        TextView tv = (TextView)findViewById(R.id.textview);
        tv.setText(foo.toString());
    }
}

RoboDaggerComponent.java

package xx.robodagger;

import javax.inject.Singleton;

import dagger.Component;

@Singleton
@Component(modules={RoboDaggerModule.class})
interface RoboDaggerComponent {

    void inject(MainActivity mainActivity);
}

RoboDaggerModule.java

package xx.robodagger;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@SuppressWarnings("unused")
@Module
class RoboDaggerModule {

    @Provides
    @Singleton
    Foo providesFoo() { return new Foo(); }
}

现在在测试目录中,

FakeFoo.java

package xx.robodagger;

class FakeFoo extends Foo {

    @Override public String toString() {
        return "bar";
    }
}

MainActivityTest.java

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import javax.inject.Inject;

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class MainActivityTest {

    TestRoboDaggerComponent testRoboDaggerComponent;

    @Inject Foo foo;

    @Before
    public void setup() {
        testRoboDaggerComponent = DaggerTestRoboDaggerComponent.builder()
            .testRoboDaggerModule(new TestRoboDaggerModule())
            .build();
        testRoboDaggerComponent.inject(this);
    }

    @Test
    public void fooBarTest() {
        assert(foo.toString().equals("bar"));
    }
}

TestRoboDaggerComponent.java

package xx.robodagger;

import javax.inject.Singleton;

import dagger.Component;

@Singleton
@Component(modules={TestRoboDaggerModule.class})
interface TestRoboDaggerComponent {

    void inject(MainActivityTest mainActivityTest);
}

TestRoboDaggerModule.java

package xx.robodagger;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;

@SuppressWarnings("unused")
@Module
class TestRoboDaggerModule {

    @Provides
    @Singleton
    Foo providesFoo() { return new FakeFoo(); }
}

1 个答案:

答案 0 :(得分:1)

删除TestRoboDaggerComponent.java,不需要

修改App.java以通过受保护的方法设置组件

@Override public void onCreate() {
    super.onCreate();
    setupComponent();
}

protected void setupComponent() {
    roboDaggerComponent = DaggerRoboDaggerComponent.builder()
            .roboDaggerModule(new RoboDaggerModule())
            .build();
}

修改TestApp.java以扩展App,并使用TestModule覆盖前面提到的方法

public class TestApp extends App {

    @Override
    protected void setupComponent() {
        roboDaggerComponent = DaggerRoboDaggerComponent.builder()
            .roboDaggerModule(new TestRoboDaggerModule())
            .build();
    }
}

最后,在实际测试中,利用Robolectric的功能指定应用程序模块

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class,
        application = TestApp.class)
public class MainActivityTest {

    private MainActivity mainActivity;

    @Before
    public void setup() {
        mainActivity = Robolectric.setupActivity(MainActivity.class);
    }

    @Test
    public void fooBarTest() {
        TextView tv = (TextView)mainActivity.findViewById(R.id.textview);
        assert(tv.getText().equals("bar"));
    }
}

请注意,实际测试中没有任何DI。 MainActivity的注入按预期方式进行,并使用覆盖的模块。如果您有一个在构造函数中使用@Injects的依赖项,则Dagger文档的解决方案是 not 而不是在测试中使用注入,而只是使用模拟对象调用普通的构造函数。这一切都说得通。我仍然认为最初报告的问题是一个错误,但无论如何。