Flutter/Dart - Unit Testing with Mockito

Flutter/Dart - Unit Testing with Mockito

This tutorial shows you how to create a unit test for Flutter application (or any other application using Dart language) using Mockito.

This tutorial shows you how to create a unit test for Flutter application (or any other application using Dart language) using Mockito.

While creating unit test for a function, sometimes you may want to mock or stub the result of other functions being called from the function under test. This tutorial shows you how to create a unit test for Flutter application (or any other application using Dart language) using Mockito.

Dependencies

There are two libraries used on this tutorial. The first one is test, which provides a standard way of writing and running tests in Dart. The other is mockito, which is used to mocks function - it’s inspired by Mockito on Java. Add the following to dev_dependencies section of pubspec.yml and run get pakcages.

  dev_dependencies:
    mockito: 4.0.0
    test: ^1.5.3

Project Structure

For example, there is a file lib/example.dart containing list of functions we’re going to test. The test files should be placed on test directory. To keep the structure clean, it’s better to follow the convention. The code and the test file should have the same file path relative to lib and test respectively and add _test to the filename of test file.

  lib
    example.dart
  test
    example_test.dart

The Code to Test

Inside example.dart, there is a simple function formatPostTitle. It has one parameter of type Post. If the post is new, the function will append [New] at the beginning of the title. To determine whether the post is new or not, it makes a call to postHelper.isNewPost.

lib/example.dart

  import 'dart:async';

  import 'package:flutter_app/post.dart';
  import 'package:flutter_app/posthelper.dart';

  class Example {
    PostHelper postHelper;

    Example() {
      this.postHelper = new PostHelper();
    }

    Example.withMocks({ this.postHelper });

    String formatPostTitle(Post post) {
      bool isNew = postHelper.isNewPost(post);

      return isNew ? '[New] ${post.title}' : post.title;
    }
  }

The Unit Test

We are going to use test package for running test. Below is the basic structure of the test file.

  main() {
    group('formatPostTitle', () {
      test('when post is new', () async {

      }

      test('when post is new', () async {

      }
    }
  }

When you run the test file, everything inside main will be executed. The group block is used to define what is being tested, while the test block is used to define each test case.

Since we only test formatPostTitle, we don’t need to care whether postHelper.isNewPost works or not. There are two cases. If the post is new, it will return true. Otherwise, it will return false. So, we need to have two test cases and for each case, we need to mock postHelper.isNewPost to return true and false respectively. That means we need to mock PostHelper class.

To create a mock of PostHelper, add the following outside main.

  class MockPostHelper extends Mock implements PostHelper {}

To mock the isNewPost method, here’s the example

  when(mockedPostHelper.isNewPost(any))
          .thenReturn(true);

It means if we add the code above in a test block, everytime postHelper.isNewPost, it will always return true.

The last thing we need to handle is checking if the result is in accordance with the expectation. We can use expect - the basic use is passing the expected value as the first argument and the result as the second argument.

  import 'package:flutter_app/post.dart';
  import 'package:flutter_app/posthelper.dart';
  import 'package:mockito/mockito.dart';
  import 'package:test/test.dart';

  import 'package:flutter_app/example.dart';

  class MockPostHelper extends Mock implements PostHelper {}

  main() {
    group('formatPostTitle', () {
      test('when post is new', () async {
        final mockedPostHelper = MockPostHelper();

        when(mockedPostHelper.isNewPost(any))
            .thenReturn(true);

        Post post = new Post(
          title: 'Flutter/Dart Tutorial',
        );

        Example example = new Example.withMocks(postHelper: mockedPostHelper);
        expect('[New] Flutter/Dart Tutorial', await example.formatPostTitle(post));      });

      test('when post is not new', () async {
        final mockedPostHelper = MockPostHelper();

        when(mockedPostHelper.isNewPost(any))
            .thenReturn(false);

        Post post = new Post(
          title: 'Flutter/Dart Tutorial',        );

        Example example = new Example.withMocks(postHelper: mockedPostHelper);
        expect('Flutter/Dart Tutorial', await example.formatPostTitle(post));      });
    });
  }

Mocking Function That Returns Future

How about mocking function that returns Future using Mockito. It’s a bit different. For example, there is a new function Future<bool> isPostActive that calls postHelper.fetchPost. fetchPost returns Future<Post> and we want to mock it in the unit test.

  import 'dart:async';

  import 'package:flutter_app/post.dart';
  import 'package:flutter_app/posthelper.dart';

  class Example {
    PostHelper postHelper;

    Example() {
      this.postHelper = new PostHelper();
    }

    Example.withMocks({ this.postHelper });

    String formatPostTitle(Post post) {
      bool isNew = postHelper.isNewPost(post);

      return isNew ? '[New] ${post.title}' : post.title;
    }

    Future<bool> isPostActive(int id) async {
      try {
        Post post = await postHelper.fetchPost(id);
        return post.active == true;
      } catch (err) {
        return false;
      }
    }
  }

Instead of using thenReturn, if the function returns Future, we have to use thenAnswer.

  when(mockedPostHelper.fetchPost(1))
    .thenAnswer((_) async => Future.value(
      new Post(
        id: 1,
        userId: 1,
        title: 'Post Title',
        content: 'Post content...',
        active: false,
      )
    )
  );

Another case is throwing error. Sometimes we need to handle if the called function returns error. You can use thenThrow for simulating error.

  when(mockedPostHelper.fetchPost(1))
    .thenThrow(new Error());

Below is the full example of unit test for isPostActive function.

  import 'package:flutter_app/post.dart';
  import 'package:flutter_app/posthelper.dart';
  import 'package:mockito/mockito.dart';
  import 'package:test/test.dart';

  import 'package:flutter_app/example.dart';

  class MockPostHelper extends Mock implements PostHelper {}

  main() {
    group('formatPostTitle', () {
      // ...
    });

    group('isPostActive', () {
      test('when post is active', () async {
        final mockedPostHelper = MockPostHelper();

        when(mockedPostHelper.fetchPost(1))
          .thenAnswer((_) async => Future.value(
            new Post(
              id: 1,
              userId: 1,
              title: 'Post Title',
              content: 'Post content...',
              active: true,
            )
          ));

        Example example = new Example.withMocks(postHelper: mockedPostHelper);
        expect(true, await example.isPostActive(1));
      });

      test('when post is inactive', () async {
        final mockedPostHelper = MockPostHelper();

        when(mockedPostHelper.fetchPost(1))
          .thenAnswer((_) async => Future.value(
            new Post(
              id: 1,
              userId: 1,
              title: 'Post Title',
              content: 'Post content...',
              active: false,
            )
        ));

        Example example = new Example.withMocks(postHelper: mockedPostHelper);
        expect(false, await example.isPostActive(1));
      });

      test('when error', () async {
        final mockedPostHelper = MockPostHelper();

        when(mockedPostHelper.fetchPost(1))
          .thenThrow(new Error());

        Example example = new Example.withMocks(postHelper: mockedPostHelper);
        expect(false, await example.isPostActive(1));
      });
    });
  }

That’s the basic examples of creating unit test with the help of Mockito for mocking dependency to other functions.

flutter mobile-apps dart

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Google's Flutter 1.20 stable announced with new features - Navoki

Google has announced new flutter 1.20 stable with many improvements, and features, enabling flutter for Desktop and Web

Top 25 Flutter Mobile App Templates in 2020

Flutter has been booming worldwide from the past few years. While there are many popular mobile app development technologies out there, Flutter has managed to leave its mark in the mobile application development world. In this article, we’ve curated the best Flutter app templates available on the market as of July 2020.

How To Succeed In Mobile App Wireframe Design?

This article covers everything about mobile app wireframe design: what to do and what not, tools used in designing a mobile or web app wireframe, and more.

What is Flutter and why you should learn it?

Flutter is an open-source UI toolkit for mobile developers, so they can use it to build native-looking Android and iOS applications from the same code base for both platforms. Flutter is also working to make Flutter apps for Web, PWA (progressive Web-App) and Desktop platform (Windows,macOS,Linux).

How much does it cost to make a Flutter app for your business?

Get a Free Quote on Android App Development, iPhone App Development, Ionic App Development, Video Development, ASO, SEO, Google Ads/Adwords, SEO for your app Idea.