I have an abstract AccountRequiredActivity that looks like this (and works fine):
public abstract class AccountRequiredActivity extends LifecycleActivity {
I solved the problem by overriding AndroidInjector's inject()
method:
@Override
public AndroidInjector<Activity> activityInjector() {
return new AndroidInjector<Activity>() {
@Override
public void inject(Activity instance) {
AccountViewModel viewModel = mock( AccountViewModel.class );
if(instance instanceof TestHomeActivity) {
((TestHomeActivity) instance).viewModelFactory = ViewModelUtil.createFor( viewModel );
}
}
};
}
It’s possible to set injected activity attribute by registering a custom ActivityLifecycleCallbacks in your TestApp in the @Before Method.
Example:
@Before
public void init(){
UserFragment fragment = UserFragment.create("foo");
viewModel = mock(UserViewModel.class);
when(viewModel.getUser()).thenReturn(userData);
when(viewModel.getRepositories()).thenReturn(repoListData);
navigationController = mock(NavigationController.class);
TestApp testApp = ((TestApp) InstrumentationRegistry.getContext().getApplicationContext());
testApp.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//will be called before the onCreate method of your activity
activity.setViewModelFactory(ViewModelUtil.createFor(viewModel));
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
fragment.viewModelFactory = ViewModelUtil.createFor(viewModel);
fragment.navigationController = navigationController;
fragment.dataBindingComponent = () -> fragmentBindingAdapters;
activityRule.getActivity().setFragment(fragment);
}
you can create own testrule
public class MyCustomRule<A extends MainActivity> extends ActivityTestRule<A> {
public MyCustomRule(Class<A> activityClass) {
super(activityClass);
}
@Override
protected void beforeActivityLaunched() {
super.beforeActivityLaunched();
// Maybe prepare some mock service calls
// Maybe override some depency injection modules with mocks
}
@Override
protected Intent getActivityIntent() {
Intent customIntent = new Intent();
// add some custom extras and stuff
return customIntent;
}
@Override
protected void afterActivityLaunched() {
super.afterActivityLaunched();
// maybe you want to do something here
}
@Override
protected void afterActivityFinished() {
super.afterActivityFinished();
// Clean up mocks
}
}
and set as ActivityTestRule
@Rule
public ActivityTestRule<MainActivity> testRule = new MyCustomRule<>(MainActivity.class);
in beforeActivityLaunched()
you can then inject your viewModelFactory
more here
Try to override dagger module for provide ViewModelProvider.Factory.
change testInstrumentationRunner 'com.eusecom.attendance.MockTestRunner' in app/build.gradle
call MockYourApplication.class in MockTestRunner
create new Mock dagger component in your MockYourApplication.class
before run testActivity override dagger component and module
Watch example https://github.com/eurosecom/Attendance/blob/master/app/src/androidTest/java/com/eusecom/attendance/DgAeaActivityTest.java
I have not used new dagger 2.11 with AndroidInjector ( i have used older dagger2 pattern ) but may be it helps.