在单元测试中模拟注入的场

And*_*Res 7 java android unit-testing mockito

我有一个Presenter使用通过Dagger注入的字段的类,它看起来像这样:

public class RssListPresenter {

    @Inject
    RssService rssService; // <-- injected field

    public RssListPresenter() {
        setupDI();
    }

    private void setupDI() {
        DaggerNetworkComponent.builder()
                .networkModule(new NetworkModule())
                .build()
                .inject(this);
    }

    public void loadItems() {
        Rss rss = rssService.getRssFeed()
        // ....
    }
}
Run Code Online (Sandbox Code Playgroud)

一切正常.现在,我想对RssListPresenter班级进行单元测试.问题是如何RssService向演示者提供模拟?

当然,我可以向演示者添加一个新方法setRssService(RssService rssService),并使用它来提供单元测试的模拟,但是为单元测试添加这个方法感觉不对.处理这个问题的正确方法是什么?

为了完整性,这里是模块和组件声明:

@Singleton
@Component(modules = NetworkModule.class)
public interface NetworkComponent {
    void inject(RssListPresenter presenter);
}

@Module
public class NetworkModule {

    @Provides
    Retrofit provideRetrofit() {
        // ... 
    }

    @Provides
    @Singleton
    RssService providePcWorldRssService(Retrofit retrofit) {
        return retrofit.create(RssService.class);
    }

}
Run Code Online (Sandbox Code Playgroud)

Dav*_*son 6

物业注入就像是不容易测试.在这种情况下,构造函数注入要好得多.将构造函数重构为如下所示:

private final RssService rssService;

@Inject
public RssListPresenter(RssService rssService) {
        this.rssService = rssService;
}
Run Code Online (Sandbox Code Playgroud)

现在您可以轻松测试它:

//mocks
RssService mockRssService;

//system under test
RssListPresenter rssListPresenter;

@Before
public void setup() {
    mockRssService = Mockito.mock(RssService.class);
    rssListPresenter = new RssListPresenter(mockRssService);
}
Run Code Online (Sandbox Code Playgroud)

你可能不应该DaggerNetworkComponent.inject(this)在里面使用RssListPresenter.相反,你应该这样,当它注入成员加入您的顶级类(可配置匕首Activity,Fragment,Service)它可以访问对象图并创建实例RssPresenter.

为什么只有把注射器中ActivityService,而不是在类似RssListPresenter?这些是由Android系统实例化的类,因此您别无选择,只能使用注入器.

为了澄清,Activity,Fragment等都是理想的注射目标.RssListPresenter等被注入的依赖.您需要配置依赖注入框架 dagger,以便它可以提供正确的依赖关系以注入注入目标.

所以你还需要编写一个@Provides方法RssListPresenter

@Provides provideRssListPresenter(RssService rssService) {
    return new RssListPresenteR(rssService);
}
Run Code Online (Sandbox Code Playgroud)

  • 值得一提的是,"Activity","Fragment"等基本原因是注入目标,因为它们是由Android框架实例化的,需要一个无参数构造函数. (2认同)
  • 问题是如何模拟注入的字段。不是如何避免它,这样你就可以轻松嘲笑。有些情况下你不能使用构造函数注入。 (2认同)