Bidev
IntermediateTesting

How do you test code that uses Riverpod providers?

Short Answer

Wrap the widget or logic under test in a ProviderScope with overrides — swapping real providers for test doubles via overrideWith or overrideWithValue — so tests never hit real network/database calls.

Riverpod's ProviderScope accepts an overrides list, letting you replace any provider with a fake implementation just for that scope. For a repository provider: overrides: [userRepositoryProvider.overrideWithValue(mockRepo)]. For an AsyncNotifierProvider with its own async logic, overrideWith lets you substitute the whole provider's implementation.

This makes it possible to test a widget's behavior across loading/data/error states deterministically, by overriding a provider to immediately return each state, rather than depending on real timing from an actual async call.

Code Example

testWidgets('shows user name when loaded', (tester) async {
  await tester.pumpWidget(
    ProviderScope(
      overrides: [
        userRepositoryProvider.overrideWithValue(MockUserRepository()),
      ],
      child: const MaterialApp(home: ProfileScreen()),
    ),
  );
  await tester.pumpAndSettle();
  expect(find.text('Ana'), findsOneWidget);
});

Common Mistakes

  • ×Using overrideWithValue for a provider whose behavior (not just its value) needs to change between tests — overrideWith gives a full replacement implementation.
  • ×Forgetting that a fresh ProviderScope is needed per test to avoid state leaking between tests.