Android单元使用Dagger 2进行测试

Pik*_*ing 50 java android unit-testing dagger-2

我有一个Android应用程序使用Dagger 2进行依赖注入.我还使用最新的gradle构建工具,它允许构建变体进行单元测试,一个用于仪器测试.我java.util.Random在我的应用程序中使用,我想模仿它进行测试.我正在测试的类不使用任何Android内容,所以它们只是常规的java类.

在我的主代码中,我Component在一个扩展Application类的类中定义了一个,但在单元测试中,我没有使用Application.我试着定义测试ModuleComponent,但匕首不会产生Component.我也尝试使用Component我在我的应用程序中定义的并交换Module构建它的时间,但应用程序Component没有inject我的测试类的方法.我如何提供Random用于测试的模拟实现?

这是一些示例代码:

应用:

public class PipeGameApplication extends Application {

    private PipeGame pipeGame;

    @Singleton
    @Component(modules = PipeGameModule.class)
    public interface PipeGame {
        void inject(BoardFragment boardFragment);
        void inject(ConveyorFragment conveyorFragment);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        pipeGame = DaggerPipeGameApplication_PipeGame.create();
    }

    public PipeGame component() {
        return pipeGame;
    }
}
Run Code Online (Sandbox Code Playgroud)

模块:

@Module
public class PipeGameModule {

    @Provides
    @Singleton
    Random provideRandom() {
        return new Random();
    }
}
Run Code Online (Sandbox Code Playgroud)

测试的基类:

public class BaseModelTest {

    PipeGameTest pipeGameTest;

    @Singleton
    @Component(modules = PipeGameTestModule.class)
    public interface PipeGameTest {
        void inject(BoardModelTest boardModelTest);
        void inject(ConveyorModelTest conveyorModelTest);
    }

    @Before
    public void setUp() {
        pipeGameTest = DaggerBaseModelTest_PipeGameTest.create(); // Doesn't work
    }

    public PipeGameTest component() {
        return pipeGameTest;
    }
}
Run Code Online (Sandbox Code Playgroud)

要么:

public class BaseModelTest {

    PipeGameApplication.PipeGame pipeGameTest;

    // This works if I make the test module extend
    // the prod module, but it can't inject my test classes
    @Before
    public void setUp() {
        pipeGameTest = DaggerPipeGameApplication_PipeGame.builder().pipeGameModule(new PipeGameModuleTest()).build();
    }

    public PipeGameApplication.PipeGame component() {
        return pipeGameTest;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试模块:

@Module
public class PipeGameTestModule {

    @Provides
    @Singleton
    Random provideRandom() {
        return mock(Random.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

tom*_*ozb 26

目前,Dagger 2(截至v.0.0.0)无法解决这个问题.你可以在这里阅读它.

有关可能的解决方法的更多信息


Igo*_*sky 6

你已经说过:

application的Component没有我的测试类的注入方法

因此,为了解决这个问题,我们可以制作一个Application类的测试版本.然后我们可以拥有您模块的测试版本.为了使它全部在测试中运行,我们可以使用Robolectric.

1)创建Application类的测试版本

public class TestPipeGameApp extends PipeGameApp {
    private PipeGameModule pipeGameModule;

    @Override protected PipeGameModule getPipeGameModule() {
        if (pipeGameModule == null) {
            return super.pipeGameModule();
        }
        return pipeGameModule;
    }

    public void setPipeGameModule(PipeGameModule pipeGameModule) {
        this.pipeGameModule = pipeGameModule;
        initComponent();
    }}
Run Code Online (Sandbox Code Playgroud)

2)您的原始Application类需要具有initComponent()pipeGameModule()方法

public class PipeGameApp extends Application {
    protected void initComponent() {
        DaggerPipeGameComponent.builder()
            .pipeGameModule(getPipeGameModule())
            .build();
    }

    protected PipeGameModule pipeGameModule() {
        return new PipeGameModule(this);
    }}
Run Code Online (Sandbox Code Playgroud)

3)您的PipeGameTestModule应该使用构造函数扩展生产模块:

public class PipeGameTestModule extends PipeGameModule {
    public PipeGameTestModule(Application app) {
        super(app);
    }}
Run Code Online (Sandbox Code Playgroud)

4)现在,在junit test的setup()方法中,在测试应用上设置此测试模块:

@Before
public void setup() {
    TestPipeGameApp app = (TestPipeGameApp) RuntimeEnvironment.application;
    PipeGameTestModule module = new PipeGameTestModule(app);
    app.setPipeGameModule(module);
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以根据自己的需要自定义测试模块.