使用Dagger 2(Robolectric和Mockito)进行单元测试

5
我是一个能翻译的助手。
我试图为一些使用 @Inject 注解的 fragment 编写测试。例如,我的应用程序的某个部分如下所示:
模块:
@Module
public class PdfFactoryModule {

    @Provides @Singleton
    PdfFactory providePdfFactory() {
        return PdfFactory.getPdfFactory();
    }
}

组件:

@Singleton
@Component(modules = PdfFactoryModule.class)
public interface CorePdfComponent {
    void inject(PagerFragment pagerFragment);
}

应用:

public class CorePdfApplication extends Application {
    @NonNull
    private CorePdfComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerCorePdfComponent.builder().build();
    }

    @NonNull
    public CorePdfComponent getComponent() {
        return component;
    }

}

PagerFragment:

public class PagerFragment extends Fragment {
@Inject PdfFactory pdfFactory;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Dagger 2
    ((CorePdfApplication) getActivity().getApplication()).getComponent().inject(this);
}

请注意,以下只是我的整个代码的片段,我只展示了这个特定依赖项的必要部分,以保持清晰。


我想进行这样的测试:

虚拟模块:

@Module
public class FakePdfFactoryModule extends PdfFactoryModule {

    @Override
    PdfFactory providePdfFactory() {
        return Mockito.mock(PdfFactory.class);
    }
}

虚假组件:

@Singleton
@Component(modules = FakePdfFactoryModule.class)
public interface FakeCorePdfComponent extends CorePdfComponent {
    void inject(PagerFragmentTest pagerFragmentTest);
}

虚假应用:

public class FakeCorePdfApplication extends CorePdfApplication {
    @NonNull
    private FakeCorePdfComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerFakeCorePdfComponent.builder().build();
    }

    @NonNull
    public FakeCorePdfComponent getComponent() {
        return component;
    }
}

测试:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, application = FakeCorePdfApplication.class)
public class PagerFragmentTest {

    PagerFragment pagerFragment;

    @Before
    public void setup() {
        pagerFragment = new PagerFragment();
        startVisibleFragment(pagerFragment);
    }

    @Test
    public void exists() throws Exception {
        assertNotNull(pagerFragment);
    }

但是DaggerFakeCorePdfComponent没有生成。我可能犯了大错误,因为我从未测试过依赖注入。我做错了什么?


如果您正在使用类路径上的Dagger进行编译,则无法创建DaggerFakeCorePdfComponent应该会带有错误,在IDE的“输出”选项卡或编译器的错误日志中。您能找到任何这样的输出吗?(另外,我看不到您在测试中使用Dagger的位置;为什么您想要将测试访问权限放在组件上,而不是从独立组件获取您的系统或依赖项?) - Jeff Bowman
它只是说错误:(14,21)错误:找不到符号变量DaggerFakeCorePdfComponent 至于测试,我想测试片段本身,但没有依赖项它将无法运行。 - Haruspik
有点冒险,但我猜测robolectric实际上没有运行正确的gradle任务来运行apt插件并为您生成类。您是否尝试过除apt之外添加testCompile <dagger-compiler>?如果没有,请尝试一下并在此处让我知道。 - Fred
我的依赖项看起来像这样:testCompile 'org.hamcrest:hamcrest-core:1.1' testCompile 'org.hamcrest:hamcrest-library:1.1' testCompile 'org.hamcrest:hamcrest-integration:1.1' testCompile "org.robolectric:robolectric:3.1.1" testCompile "org.robolectric:shadows-support-v4:3.1.1" compile 'com.google.dagger:dagger:2.6.1' apt "com.google.dagger:dagger-compiler:2.6.1"你想让我在末尾添加testcompile "com.google.dagger:dagger-compiler:2.6.1"吗?它给了我一个错误:Error:(50, 0) Could not find method testcompile() for arguments [com.google.dagger:dagger-compiler:2.6.1] - Haruspik
我知道你已经接受了答案,但是应该使用大写字母“C”来表示“testCompile” :) - Fred
2个回答

10

我的建议是“在测试中不要使用匕首(dagger)”。

只需将您的代码更改为以下内容:

public class FakeCorePdfApplication extends CorePdfApplication {
    @NonNull
    private CorePdfComponent component = mock(CorePdfComponent.class);

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

    @NonNull
    public CorePdfComponent getComponent() {
        return component;
    }
}

而且:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21, application = FakeCorePdfApplication.class)
public class PagerFragmentTest {

    PagerFragment pagerFragment;

    @Before
    public void setup() {
        pagerFragment = new PagerFragment();
        CorePdfComponent component = ((CorePdfApplication)RuntimeEnvironment.application).getComponent();

        doAnswer( new Answer() {
          Object answer(InvocationOnMock invocation) {
           fragment. pdfFactory = mock(PdfFactory.class);
           return null;
          }
        }).when(component).inject(pageFragment);
        startVisibleFragment(pagerFragment);
    }

    @Test
    public void exists() throws Exception {
        assertNotNull(pagerFragment);
    }
}

现在可以工作了 :) 谢谢! - Haruspik
6
“在测试中不要使用Dagger”是一种明确的声明。 - Chisko
@Chisko 确实!我不是母语为英语的人。我的意图是说-在这种类型的测试中不要使用Dagger。 - Eugen Martynov

1

你可以尝试:

androidTestApt "com.google.dagger:dagger-compiler:<version>"

我遇到了类似的问题,它对我起作用了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接