A Comprehensive Guide to Mockito in Flutter
Tags: flutter, programming, testing, mockito
Published: 2021-12-16 05:40:04

No one likes testing! Everyone thinks testing is a boring job. But trust me, testing a software is as important as developing a software.

Imagine, if you spend days and months building your app and finally when it went live, the app started crashing. What if you had tested all the functionalities before making it live?

So, testing is a very important phase of Software Development Life Cycle. Even if you hate it, you have to do it.

But, in this article i will make sure you will end up liking the process of testing.

![Celebration](https://i.pinimg.com/originals/88/5d/7c/885d7c27467f1e976d0c873336facc24.gif)

So, what are you gonna learn in this article?

Just one thing - **How to Unit test your code using Mockito!**

Before i begin, if you wanna read about Unit Testing, check out my latest tweet which talks about a basic introduction to Unit Testing in Flutter:

![Tweet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dh03h2i2gwl1e818c3o6.png)
  
https://twitter.com/gopinathanaswin/status/1470617070559711234?s=21

Now, lets get to the fun part. 

## What is Mockito?

Mockito is a package in Flutter that helps you create Mock Dependencies of classes while testing your code.

**Let me give you an example:**
Imagine a feature that you are testing requires data to be fetched from an external DB such as Firebase/Supabase. 
When you are testing your code offline you cant possibly gather data from the DB right? Or even if you are online, you dont wanna wait for the actual data to return in order to test the app right?

So, what will you do then?

![Joey Thinking](https://i.pinimg.com/originals/f2/6c/be/f26cbec6fb6c5d9bf65789e4ce69479b.jpg)

We use **Mockito** to create a fake class which will use dummy data as input for your tests !!

Before we get started with the code, lets add dependencies for two packages in pubspec.yaml :

```yaml
dev_dependencies:
  mockito: ^5.0.10
  build_runner: ^2.1.2
```

_Note: I have added the packages in the `dev_dependencies` section. This is because, we are not gonna use these packages in the actual application code._

Also, the package versions may vary when you are reading this article. Do checkout [pub.dev](https://pub.dev/) to get the latest versions.

Let's create a new file `cat.dart` in the `test` folder:

```dart
class Cat {
  String sound() => "Meow";
  bool eatFood(String food, {bool? hungry}) => true;
  Future<void> chew() async => print("Chewing...");
  int walk(List<String> places) => 7;
  void sleep() {}
  void hunt(String place, String prey) {}
  int lives = 9;
}
```

I have used the example which is given in the official docs of mockito in pub.dev

Next, create a file `cat_test.dart` file which will contain all the codes to test the class.
Add the following contents to the file:

```dart
import 'package:mockito/annotations.dart';
import 'cat.dart';

@GenerateMocks([Cat])
void main() {

}
```

`@GenerateMocks([Cat])` is used to create a Mock Class for our `Cat` class. 

Now, head over to the terminal and type the following command:

```bash
dart run build_runner build
```

This will generate the mock file for us with the name `cat_test_mocks.dart` which contains the `MockCat` class which we are gonna use for our testing.

Import this new file into our `cat_test.dart` file:

```dart
import 'cat_test.mocks.dart';
```

Now, head over to the `main` function and initialise an object for class `MockCat`.

```
var cat = MockCat();
```

Now, let's verify some methods. But, what is verify in testing ?

**Verify**: It means we are verifying a method if it was invoked in that particular scope or not.

I will explain this better with an example. Append the following code inside the `main()` function:

```dart
test('verify sound',() {
  when(cat.sound()).thenReturn('meow');

  cat.sound();

  verify(cat.sound());
});
```

We have defined a test block that performs verify operation on the `sound()` method.

The first line:

```dart
when(cat.sound()).thenReturn('meow');
```
is known as **Stubbing**. 
Oh come on! What is Stubbing now? I will explain this a bit later, but for now just imagine we have a method `sound()`, that returns 'meow'.

Now, the second line:

```dart
cat.sound();
```
we invoke the `sound()` method.

Finally, the last line:

```dart
verify(cat.sound());
```

we are verifying if the mentioned method with the given parameter list was invoked in this scope or not.

So, this test will pass since it was invoked in line 2. But what if we write verify like this:

```dart
verify(cat.sound('Bow'));
```

This will fail, because the `sound()` method was not invoked in this scope with a String parameter 'Bow'.

So, this is how `verify` works in mockito.

**Where is this helpful ?**
This is helpful to know whether a method was invoked during the flow of a unit.
**For example**: Verify if the `validatePassword()` method was called while creating a user.

But, there are some more interesting variants of `verify` known as `verifyInOrder()`, `verifyNever()`, and `verifyZeroInteractions()`.

1. verifyInOrder() takes in a list of methods, to verify if they were invoked in that particular order.

2. verifyNever() takes in a method, to verify if it was never invoked.

3. verifyZeroInteractions() takes in a mock object (not a method), to verify if that object was never called in the scope of the test.

Now, lets jump into **Stubbing**.

Stubbing is the process of overriding the behaviour of a method belonging to the mock class instance.

Example:

Consider a method that returns 'Dart':

```dart
String getLang() => 'Dart';
```

We stub the method to return 'Flutter' instead.

```dart
when(obj.getLang()).thenReturn('Flutter');
```

Now, no matter how many times you call the method `getLang()`, it will always return 'Flutter' as opposed to its declaration in its class.

This is helpful when you wanna test your methods for different return data.

Let's consider our `MockCat` class and test a stubbing:

```dart
test('stubbing',() {
  when(cat.sound()).thenReturn('Flutter');
  expect(cat.sound(), 'Flutter');
});
```

In the normal flow `cat.sound()` should return 'Meow', but after stubbing it will always return 'Flutter'.

If a method invocation matches multiple stubs, the one which was declared last will be used. It is worth noting that stubbing and verifying only works on methods of a mocked class; in this case, an instance of `MockCat` must be used, not an instance of `Cat`.
  
## Best Practices while working with Mockito

- Whenever you make changes to the class that you are mocking, always re-generate the mock class using the build command that i mentioned above.

- Always Stub your method before verifying it in a test block. Otherwise, it will return an error like the following:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/grcsdmtloiwvm1slfx44.png)

- Testing with real objects is preferred over testing with mocks - if you can construct a real instance for your tests, you should!

---

If you liked this article, dont forget to hit the like button and share it with your friends and colleagues.

Follow me on Twitter [@GopinathanAswin](https://twitter.com/GopinathanAswin) where i regularly share my learnings in Dart and Flutter 💙


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m90v4tivz5xqzf51xu2n.png)