Using Mockito in Flutter
Tags: computerscience, productivity, flutter, programming
Published: 2022-03-28 15:30:49

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:paragraph -->
<p>We will cover briefly:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Setup Mockito</li><li>Mocking repository using Mockito</li><li>Write unit tests for repository</li><li>Write unit tests for the view model</li><li>(Optional) Code coverage</li></ol>
<!-- /wp:list -->

{% youtube pxJGOJI6fik %}

<!-- wp:heading {"level":3} -->
<h3>Setup Mockito</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>There are often times when unit tests depend on classes that fetch data from live web services or databases. This is inconvenient for a few reasons:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Calling live services or databases slows down test execution.</li><li>It is difficult to test all possible success and failure scenarios by using a live web service or database.</li></ul>
<!-- /wp:list -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/0*OAL7zVW-0YNdZcV2.png" alt="Mockito"/><figcaption>Mockito</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>You can mock dependencies by creating an alternative implementation of a class. by making use of the <a href="https://pub.dev/packages/mockito" rel="noreferrer noopener" target="_blank">Mockito package</a> as a shortcut.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Following is the general idea behind <strong>Mockito</strong></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Rather than relying on a live web service or database, you can “mock” these dependencies. Mocks allow emulating a live web service or database and return specific results depending on the situation.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>We use the <code><a href="https://pub.dev/packages/mockito" target="_blank" rel="noreferrer noopener">mockito</a></code> package for writing unit tests and for generating the implementation it relies on <code><a href="https://pub.dev/packages/build_runner" target="_blank" rel="noreferrer noopener">build_runner</a></code>. Add the plugins to your <code>pubspec.yaml</code> file</p>
<!-- /wp:paragraph -->

```yaml
# pubspec.yaml
dependencies:
  mockito: ^5.1.0
dev_dependencies:
  build_runner: ^2.1.7
```

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Detailed description <a href="https://pub.dev/packages/mockito" rel="noreferrer noopener" target="_blank">here</a>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3>Mocking repository using&nbsp;Mockito</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Before starting this, let's see the architecture which we used for our app</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*vupA5B_V6h6uFSj0ahm5iQ.png" alt="The architecture used in the app"/><figcaption>The architecture used in the&nbsp;app</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>For each of the screens, we have the following:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/repository/home_repo.dart" target="_blank" rel="noreferrer noopener"><strong>Repository</strong></a>: Which handles our business logic</li><li><a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/view_models/home.viewmodel.dart" target="_blank" rel="noreferrer noopener"><strong>ViewModel</strong></a>: Bridge between the UI and the repository</li><li><a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/view/home.view.dart" target="_blank" rel="noreferrer noopener"><strong>View</strong></a>: Actual screen visible to the user</li><li><a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/model/carousel.model.dart" target="_blank" rel="noreferrer noopener"><strong>Model</strong></a>: Response being cast to models, in order to be consumed in the view.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4>Repository tests using&nbsp;Mockito</h4>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>This is what our <a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/repository/home_repo.dart" rel="noreferrer noopener" target="_blank">home repository </a>looks like,</li></ul>
<!-- /wp:list -->

```dart
abstract class HomeRepo {
  Future<CarouselModel> fetchData();
}
class HomeRepoImpl extends HomeRepo {
  @override
  Future<CarouselModel> fetchData() async {
    await Future.delayed(const Duration(milliseconds: 1800));
    final resp = await  rootBundle.loadString('assets/data/first_screen.json');
    return carouselModelFromJson(resp);
  }
}
```

<!-- wp:paragraph -->
<p>In the above snippet, we are creating a manual delay in order to simulate the network delay, and afterward, we simply fetch our JSON file (present under the assets).</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>For mocking our repository, we first create a file <code>home_repo_test.dart</code>under test folder as below</li></ul>
<!-- /wp:list -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*WZzvyfRal0p12vA_O9j-HQ.png" alt="Repository testing using Mockito"/><figcaption>Repository testing using&nbsp;Mockito</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: The tests should follow <code>test/folder_name/&lt;name&gt;_test.dart</code> pattern</p></blockquote>
<!-- /wp:quote -->

<!-- wp:list -->
<ul><li>Inside the file, we add the annotation <code>@GenerateMocks([HomeRepoTest])</code> to the main function to generate a <code>MockHomeRepoTest</code> class with <code>mockito</code>.</li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>By annotating a library element (such as a test file’s <code>main</code> function, or a class) with <code>@GenerateMocks</code>, you are directing Mockito's code generation to write a mock class for each "real" class listed, in a new library.</p></blockquote>
<!-- /wp:quote -->

```dart
// IMPORTS OMITTED FOR BREVITY
class HomeRepoTest extends Mock implements HomeRepo {}
@GenerateMocks([HomeRepoTest])
Future<void> main() async {
}
```

<!-- wp:paragraph -->
<p><strong>HomeRepoTest</strong>: The mock class which will be referred to in the generated class</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>MockHomeRepoTest</strong>: The generated mock class which implements the functions inside the <code>HomeRepo</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next, generate the mocks running the following command:</p>
<!-- /wp:paragraph -->

```dart
flutter pub run build_runner build
```

<!-- wp:paragraph -->
<p>The generated mocks will be located in <code>home_repo_test.mocks.dart</code>. Import this file to use them inside your test file.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>We should see something like this if all the above steps were done correctly</li></ul>
<!-- /wp:list -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*-wQjuyaBqzevSXZhrbvu1A.png" alt="Mockito generated class"/><figcaption>Mockito generated class</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:heading {"level":3} -->
<h3>Write unit tests for repository</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Let’s write the unit tests for the repository now, with all the necessary setup done in the previous step.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>We will initialize our mock repository inside the <code>setUpAll</code></li></ul>
<!-- /wp:list -->

```dart
Future<void> main() async {  
  late MockHomeRepoTest homeRepo;
  setUpAll(() {
    homeRepo = MockHomeRepoTest();
  });
  test('test fetchData', () async {
    final model = CarouselModel();
    when(homeRepo.fetchData()).thenAnswer((_) async {
      return model;
    });
    final res = await homeRepo.fetchData();
    expect(res, isA<CarouselModel>());
    expect(res, model);
  });
  test('test fetchData throws Exception', () {
    when(homeRepo.fetchData()).thenAnswer((_) async {
     throw Exception();
    });
    final res = homeRepo.fetchData();
    expect(res, throwsException);
  });
}
```

<!-- wp:list -->
<ul><li>We have two tests inside the repository: For the first one, we use the <code><a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener" target="_blank">when</a></code>, <code><a href="https://pub.dev/documentation/mockito/latest/mockito/PostExpectation/thenAnswer.html" rel="noreferrer noopener" target="_blank">thenAnswer</a></code>APIs provide a stubbing mechanism. Once stubbed, the method will always return the stubbed value regardless of how many times it is called.</li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener" target="_blank"><strong>when</strong></a>: Creates a stub method response. Mockito will store the fake call and pair the exact arguments given with the response. The response generators from Mockito include<code>thenReturn</code>, <code>thenAnswer</code>, and <code>thenThrow</code>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><a href="https://pub.dev/documentation/mockito/latest/mockito/PostExpectation/thenAnswer.html" rel="noreferrer noopener" target="_blank"><strong>thenAnswer</strong></a>: Stores a function which is called when this method stub is called. The function will be called, and the return value will be returned.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>We return the <code>CarouselModel</code> from the stub and use the <strong>expect</strong> to assert that <code>actual</code> matches <code>matcher</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In our case, we expect it to be of type <code>CarouselModel</code> using <a href="https://api.flutter.dev/flutter/package-matcher_matcher/isA.html" rel="noreferrer noopener" target="_blank">isA</a></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>For the second test, we throw an Exception from the stub. We expect the <code>actual</code> matches <code>throwsException</code> which is a matcher for functions that throw Exception.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>Write unit tests for the view&nbsp;model</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We will first initialize our mock home repository and the view model inside the <code>setUpAll</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We pass in the Mock repository <code>MockHomeRepoTest</code>to our view model, as it expects the repository as a required parameter.</p>
<!-- /wp:paragraph -->

```dart
Future<void> main() async {
  late MockHomeRepoTest homeRepo;
  late HomeViewModel viewModel;
  setUpAll(() {
    homeRepo = MockHomeRepoTest();
    viewModel = HomeViewModel(repo: homeRepo);
  });
  test('test fetchData', () async {
    final model = CarouselModel();
   when(homeRepo.fetchData()).thenAnswer((_) async {
     return model;
   });
   await viewModel.fetchData();
   expect(viewModel.homeModel, model);
  });
}
```
<!-- wp:list -->
<ul><li>In the test above, we use the <code><a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener" target="_blank">when</a></code>, <code><a href="https://pub.dev/documentation/mockito/latest/mockito/PostExpectation/thenAnswer.html" rel="noreferrer noopener" target="_blank">thenAnswer</a></code>APIs</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>We call the <code>homeRepo.fetchData()</code> using the <code><a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener" target="_blank">when</a></code> and return the stub response as the <code>CarouselModel</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Next, we call the actual function <code>fetchData()</code> from inside the view model using <code>viewModel.fetchData()</code></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Finally, we expect it to be of type <code>CarouselModel</code> in the matcher, since we are setting the response from the repository to the model.</p>
<!-- /wp:paragraph -->

```dart
// HomeViewModel
Future<void> fetchData() async {
  isLoading = true;
  _homeModel = await repo.fetchData();
  isLoading = false;
  notifyListeners();
}
```

<!-- wp:heading {"level":3} -->
<h3>Code coverage</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In case you are using Android Studio, you can simply right-click on the test and <strong>run tests with Coverage</strong></p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*S9Zl-URbtNFqI3oDTjzMYA.png" alt="Code Coverage using Android Studio"/><figcaption>Code Coverage using Android&nbsp;Studio</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>For VSCode, install the following extensions</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><a href="https://marketplace.visualstudio.com/items?itemName=Flutterando.flutter-coverage" rel="noreferrer noopener" target="_blank">Flutter Coverage</a></li><li><a href="https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters" rel="noreferrer noopener" target="_blank">Coverage Gutters</a></li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Execute the following command</p>
<!-- /wp:paragraph -->

```dart
flutter test --coverage
```
<!-- wp:paragraph -->
<p>This will generate the <code>lcov.info</code>which contains the coverage information.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*bR1U1PB9zjPSAExubwDH3A.png" alt=""/><figcaption>Code Coverage</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Now, click on the testing icon on the left side of the VSCode and you can see your code coverage. <strong>Good article </strong><a href="https://xeladu.medium.com/show-test-coverage-of-a-flutter-app-in-visual-studio-code-7e26c3b94aaf" rel="noreferrer noopener" target="_blank"><strong>here</strong></a></p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*Lk5clSFhqunjsgAZsqpZgQ.png" alt="Code coverage of view models"/><figcaption>Code coverage of view models</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><a rel="noreferrer noopener" href="https://github.com/AseemWangoo/dynamism" target="_blank"><em>Source code.</em></a>

{% youtube pxJGOJI6fik %}

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>