Используя Кинжал и Robolectric с тестовым приложением


Я использую шаблон MVP с фрагментом (GalleryFragment), где класс приложения(MainApplication) Источники MainActivityRepository и GalleryFragmentPresenter(сгруппированы как DIModules), которые предоставляются фрагменту через инъекцию поля.

Чтобы проверить GalleryFragment в изоляции, моя идея состояла в том, чтобы использовать Robolectric configuration(@Config), чтобы полностью заменить MainApplication пользовательским TestApplication источником mockDIModules.

GalleryFragmentTest работает до startFragment(galleryFragment), но я получаю NullPointerException в MainApplication.getComponent().inject(this); внутри GalleryFragment.

Я подозреваю, что это потому, что эта строка в частности, использует MainApplication, в то время как все остальное имеет дело с TestApplication, установленным Robolectric @Config, но я не уверен, и я ищу совет о том, как успешно запускать тесты, используя этот пользовательский TestApplication.

В процессе поиска возможных решений я узнал об использовании AndroidInjector из библиотеки поддержки Dagger, которая полностью избавится от MainApplication.getComponent().inject(this);, но будет ли это работа? https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3

GalleryFragment.java

public class GalleryFragment extends Fragment {
    @Inject
    public MainActivityRepository mRepository;
    @Inject
    public GalleryFragmentPresenter mGalleryFragmentPresenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MainApplication.getComponent().inject(this);   //NullPointerException here
        mGalleryFragmentPresenter.initialize(mRepository, value);
    }
}

Димодулы.java

@Module
public class DIModules {
    @Provides
    public GalleryFragmentPresenter provideGalleryFragmentPresenter(){
        return new GalleryFragmentPresenter();
    }
    @Provides
    @Singleton
    public MainActivityRepository provideMainActivityRepository(){
        return new MainActivityRepository();
    }
}

Аппкомпонент.java

@Singleton
@Component(modules = DIModules.class)
public interface AppComponent {
        void inject(GalleryFragment galleryFragment);
}

Основное приложение.java

public class MainApplication extends Application {
    public static AppComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        Realm.init(this);
        component = buildComponent();
    }
    public static AppComponent getComponent() {
        return component;
    }
    protected AppComponent buildComponent(){
        return DaggerAppComponent
                .builder()
                .dIModules(new DIModules())
                .build();
    }
}

Тестовое приложение.java

public class TestApplication extends Application {
    public static AppComponent component;

    @Override
    public void onCreate() {
        super.onCreate();
        component = buildComponent();
    }
    public static AppComponent getComponent() {
        return component;
    }
    protected AppComponent buildComponent(){
        return DaggerAppComponent.builder()
                .dIModules(new mockDIModules())
                .build();
    }
}

GalleryFragmentTest.java

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class,
        application = TestApplication.class)
public class GalleryFragmentTest {
    @Test
    public void allItemTabTest() throws Exception {
        GalleryFragment galleryFragment = GalleryFragment.newInstance(value);
        startFragment(galleryFragment);
        assertNotNull(galleryFragment);
    }
}

Я использую dagger, dagger-android-support, dagger-compiler версия 2.14.1 и robolectric:3.6.1

1 3

1 ответ:

Конечно, это null. Ваш фрагмент все еще пытается работать с производственным приложением, пока вы делаете что-то в тестовом приложении.

Измените код инъекции на следующий:

((MainApplication) getContext().getApplicationContext()).getComponent().inject(this);

А также сделайте метод в вашем приложении getComponent() не статическим, поэтому тестовое приложение переопределяет его.

Другой вариант-изменить ваш TestApplication на следующий:

public class TestApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        buildComponent();
    }

    private void buildComponent(){
        Application.component = DaggerAppComponent.builder()
                .dIModules(new mockDIModules())
                .build();
    }
}