Isolated Fragment testing

How to initialize activity ViewModel without launching activity and test the Fragment using FragmentScenario in isolated testing.

Hello,

Dependency injection is the best way to do this. Koin, Hilt etc. allow you to inject your ViewModels instead of directly using the view model providers. This allows you to instantiate an instance of the shared viewmodel you want to test, presumably with a certain state that may be required for your isolated fragment test, in the setup of your test. Then you run the scenario and go from there.

So if you were using Koin and setting up your viewmodel in a module

lateinit var yourViewModel: YourViewModel

fun setup(){
loadKoinModules(
module(override = true) {
viewModel {
yourViewModel = YourViewModel()
yourViewModel
}
})
yourViewModel.
}

Does that make sense?

To initialize an Activity’s ViewModel without launching the Activity and then test a Fragment in isolation using FragmentScenario, you can follow these steps in your Android instrumentation tests:

  1. Create a TestViewModel:
  • First, create a test-specific ViewModel that extends the actual ViewModel class used in your activity. This test ViewModel should have a constructor that takes a custom ViewModelProvider.Factory or a mocked one.

javaCopy code

public class TestViewModel extends YourViewModel {
    public TestViewModel(ViewModelProvider.Factory factory) {
        super(factory);
    }
}
  1. Create a TestFragment:
  • Create a test-specific Fragment that uses the TestViewModel instead of the actual ViewModel. In the Fragment’s onCreate method, initialize the ViewModel using the ViewModelProvider with a mocked ViewModelProvider.Factory.

javaCopy code

public class TestFragment extends YourFragment {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(
            ApplicationProvider.getApplicationContext());
        viewModel = new ViewModelProvider(this, factory).get(TestViewModel.class);
    }
}
  1. Write a Test Using FragmentScenario:
  • In your Android instrumentation test, use FragmentScenario to launch the TestFragment and perform your tests on it. You can use launchFragmentInContainer to launch the Fragment and set the FragmentFactory to use the test-specific Fragment.

javaCopy code

@RunWith(AndroidJUnit4.class)
public class YourFragmentTest {
    @Before
    public void setUp() {
        // Initialize any required dependencies or mocks here.
    }

    @Test
    public void testYourFragment() {
        // Create a TestViewModelFactory or mock one if necessary.
        ViewModelProvider.Factory factory = new TestViewModelFactory();

        // Set up the FragmentScenario with the test-specific Fragment and ViewModel factory.
        FragmentScenario<TestFragment> scenario = FragmentScenario.launchInContainer(
            TestFragment.class, null, R.style.AppTheme, factory);

        // Perform your UI tests on the Fragment.
        scenario.onFragment(fragment -> {
            // Test your Fragment here using the TestViewModel.
            // For example, you can access the ViewModel via fragment.viewModel.
        });
    }
}

In this setup, you’re using a test-specific ViewModel and Fragment to isolate your tests from the actual Activity. The FragmentScenario allows you to test the Fragment in isolation. Make sure to replace YourViewModel, YourFragment, and TestViewModelFactory with your actual ViewModel, Fragment, and ViewModel factory classes.

By doing this, you can initialize the ViewModel without launching the actual Activity and test the Fragment independently, which is useful for unit testing and maintaining isolation in your UI tests.