# Why Choose Riverpod? - Testing

> This post is based off a presentation I did at Devfest 2023 in Cape Town on 23 Nov 2023. [VIDEO](https://youtu.be/tUH4KD2GUgQ) | [PRESENTATION](https://www.canva.com/design/DAF0PW9xADM/rpt3TKfDU-waodWHH6DOvQ/view)

---

Previously we covered the `ProviderScope`, the secret sauce as I like to call it, finally we are going to take a look at just how much everything simplifies our lives when it comes to testing.

---

Testing is probably one of my favourite reasons to use Riverpod, just because of how simple it makes it.

Widget testing is where we bring back our `ProviderScope`

```dart
extension PumpApp on WidgetTester {
  Future<void> pumpApp(
    Widget widget, [
    List<Override> overrides = const [],
  ]) async {
    return pumpWidget(
      ProviderScope(
        overrides: overrides,
        child: MaterialApp(
          home: Scaffold(
            body: widget,
          ),
        ),
      ),
    );
  }
}
```

Above is an extension I put together to make my life easier when it comes to testing, I make use of `pumpApp` instead of `pumpWidget` as it extends on `pubpWidget` but also allows me to easily wrap some boilerplate around my tests.

In the above example, I am wrapping every widget that gets tested with `ProviderScope` and also add support for optionally passing in an array of overrides to said `ProviderScope`.

An extension like this can also easily include things like `materialApp`, `Scaffold` and even navigation observers.

```dart
late MockConnectivityProvider mockConnectivityProvider;

setUp(() {
 mockConnectivityProvider = MockConnectivityProvider();

 when(() => mockConnectivityProvider.isOnline).thenReturn(true);
});

testWidgets('should show OnlineIndicator', (tester) async {
  await tester.pumpApp(
    widget,
    [
      connectivityProvider.overrideWith((_) => mockConnectivityProvider),
    ],
  );

  expect(OnlineIndicator, findsOneWidget);
});
```

Here we have a simple examples where we testing the `OnlineIndicator` widget which replies on the `connectivityProvider`, which is a network listener to verify that the device is both connected and is able to access the Internet.

This `connectivityProvider` as you may have guess is also a Riverpod provider, and as you can see in the `setUp` function we are mocking the response from that providers `isOnline` method to `true`, aka the devise in online.

With the `pumpApp` we are overriding the provider with our mocked one, and then in the test we simply verify that the `OnlineIndicator` does in fact renders.

### Mocking State

When it comes to mocking the dat from any Riverpod `StateNotifier`, it is about as simple:

```dart
await tester.pumpApp(
  widget,
    [
      createTripProvider.overrideWith((_) => mockCreateTripNotifier
        ..state = CreateTripState.initial().copyWith(jobs: mockJobs)),
     ],
  );
```

Much like above we would have setup a `MockTripNotifierClass`, which would look slightly different to a normal mock:

```dart
class MockCreateTripNotifier extends StateNotifier<CreateTripState>
    with Mock
    implements CreateTripNotifier {
  MockCreateTripNotifier() : super(CreateTripState());
}
```

Then e simply access the state directly within the override and assign it an updated value.

### External Packages

Another reason I love Riverpod for testing is when it comes to external packages and their ability to allow them to be very easily mocked.

One that is extensively used throughout our application is Firestore, to normally be able to mack this it would need to be an argument on the class or function whereby the instance is passed into.

Riverpod makes that much simpler. which is why within our application we have `firestoreProvider` which gets overridden with `FirebaseFirestore.instance` within the `ProviderScope` during the applications startup.

As you can by now tell, this means that `Firestore` can be directly accessed anywhere we are making use of Riverpod.

```plaintext
//main
firestoreProvider.overrideWith((_) => FirebaseFirestore.instance),

//Mock
late MockDocumentReference mockDocumentReference;

mockDocumentReference = MockDocumentReference();

overrides: [
  firestoreProvider.overrideWith((_) => mockFirestore),
]

when(() => mockFirestore.doc('drivers/driver_id'))
    .thenReturn(mockDocumentReference);
when(() => mockDocumentReference.update(payload))
    .thenAnswer((_) async => Future.value());
```

Now when looking from a testing perspective and considering the other examples with the excerpts in the code above you can see how much simpler Riverpod makes mocking an external packages, especially ones like the Firebase packages that are exposing singletons.

---

I hope you found this interesting, and if you have any questions, comments, or improvements, feel free to drop a comment. Enjoy your development journey :D

Thanks for reading.

---

* [What is Riverpod?](https://remelehane.dev/what-is-riverpod)
    
* [Riverpod Extensions](https://remelehane.dev/riverpod-extensions)
    
* [Accessing the Providers](https://remelehane.dev/accessing-the-providers)
    
* [ProviderScope](https://remelehane.dev/providerscope)
    
* [Testing](https://remelehane.dev/testing)
