robolectric - Dagger2在Test中不生成组件

标签 robolectric dagger-2

根据 Dagger 2 文档

我正在尝试根据Dagger2's documentation设置测试环境

(仅供引用,我已在 Dagger 1 中成功完成了此操作。)

问题具体在于,虽然 Dagger2 正确生成了 DaggerRoboDaggerComponent(如 App.java 中使用的),但它没有生成 DaggerTestRoboDaggerComponent(如 MainActivityTest.java 中使用的)。我检查了目录结构以确保它没有隐藏在某个不起眼的地方,并完成了必要的清理、重建、无效缓存/重新启动等操作。

如果有人能让我知道我的方法的错误,我将不胜感激。提前致谢。

您可以clone the project here

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

构建.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"
}

应用程序.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(); }
}

最佳答案

删除TestRoboDaggerComponent.java,不需要

修改App.java以通过 protected 方法设置组件

@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的强大功能来指定Application模块

@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 的注入(inject)按预期进行,并使用重写的模块。如果您有在构造函数中使用 @Injects 的依赖项,则 Dagger 文档的解决方案是在测试中使用注入(inject),而是仅使用模拟对象调用普通构造函数。这都是有道理的。我仍然认为最初报告的问题是一个错误,但无论如何。

关于robolectric - Dagger2在Test中不生成组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43545400/

相关文章:

android - 如何在 Kotlin 中使用 Dagger 的 2 @Named 限定符

java - `createActivity` 和 `shadowOf` 有什么区别?

java - 如何在 robolectric 测试中模拟/ stub 对象?

android - (DAGGER-ANDROID) 不能在 Espresso 测试中使用 @Inject 并且不能使用 mockWebServer

android - Dagger 2 无法从子组件注入(inject)

kotlin - 无需在 Dagger 中使用组件即可注入(inject) Kotlin 成员字段

android - 与模拟器和 Web 相比,真实 Android 设备中的 Retrofit 响应时间更慢

gradle - 在Robolectric中使用多个res文件夹

android - 尝试使用 Gradle、Robolectric 和 Travis CI 测试 Android 应用程序时出现 NoClassDefFoundError

android - Multidex 后 Robolectric 单元测试失败