Unit Testing with “Bloc”
When we left off, we had a working login flow but we were missing one crucial piece: unit tests.
The login flow consisted of two blocs (business logic components):
LoginBloc. In this article, we’re going to write some unit tests to ensure that our business logic is robust and durable. Let’s get started!
We’re going to start off by writing the tests for our
AuthenticationBloc. First, let’s recap the role of the
AuthenticationEvents our bloc responded to were:
AppStarted dispatched when the Flutter application first loads. It will notify bloc that it needs to determine whether or not there is an existing user.
LoggedIn dispatched on a successful login. It will notify the bloc that the user has successfully logged in.
LoggedOut dispatched on a successful logout. It will notify the bloc that the user has successfully logged out.
In response to those events, our
AuthenticationBloc emitted an
AuthenticationState which looked something like:
We have to extend
Equatable in order to allow us to check if two instances of
AuthenticationState are equal.
Now that we’ve recapped the function of the
AuthenticationBloc we’re ready to finally start writing some tests.
To get started, we simply need to import
flutter_test, and the
mockito package along with our authentication bloc. In our
setUp, we instantiate a new instance of
AuthenticationBloc to ensure that each test is run under the same conditions and does not influence subsequent tests. In addition, we are using mockito to create a mock instance of the
UserRepository which is a dependency of the
Our first test is just testing that our initialState is what we expect…nothing too fancy. Our second test is just a sanity check as well to make sure that when dispose is called the state of the bloc is not updated.
flutter test our first two tests should be passing!
The remaining tests are what we really care about. If we take the
AppStarted group as an example, all we need to do is setup our expectation of what events the bloc will yield. In this case, when we dispatch an
AppStarted event, we expect that the bloc will yield an
AuthenticationUninitialized state followed by an
AuthenticationUnauthenticated state because we have mocked our
The remaining groups have very similar flows and should all make sense now.
Now that we have the
AuthenticationBloc unit tested we can move on to the
Again, let’s recap what the role of the
LoginStates. We only responded to one
LoginEvent in our example:
In response to
LoginButtonPressed, our bloc emitted a
LoginState which looked like:
Now we can jump into the tests.
Again, we have our initialState test and our dispose sanity check. Our main logic in the
LoginBloc was handling the
LoginButtonPressed event and returning a token on a success.
The test is very simple: we set up our expectation and then dispatch our event. In this case, we expect that the
LoginBloc will yield
LoginInitial followed by a
LoginLogin and lastly a
LoginInitial in response to a
If we run our tests with
flutter test we should see that all of them are passing 🎉 🎉 🎉.
As always, if you enjoyed this exercise as much as I did you can support me by ⭐️the repository, or 👏 for this story.