Используя Кинжал и 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 ответ:
Конечно, это
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(); } }