Introduction
When testing BLoCs, you often need to isolate the business logic from external dependencies like repositories, API clients, or databases. Mocking allows you to replace real implementations with controlled test doubles. Mocktail is a modern, null‑safe mocking library for Dart that works seamlessly with Flutter and BLoC. This guide covers how to use Mocktail to create mocks, stub methods, verify interactions, and test asynchronous code.
Why Mocktail?
- Null‑Safe – Fully supports Dart's null safety.
- No Code Generation – Unlike Mockito, Mocktail doesn't require running
build_runner. - Simple API – Clean, expressive syntax.
- Works with Flutter – Compatible with all Flutter and Dart projects.
- Integration with
bloc_test– Seamlessly used insideblocTest.
Setting Up Mocktail
Add Mocktail to your pubspec.yaml dev dependencies:
Creating a Mock
To create a mock, extend Mock and implement the class you want to mock. You can do this inline or as a separate class.
Stubbing Methods
Use when() to define what a mocked method should return or do when called. Use thenAnswer for futures/streams, thenReturn for synchronous values.
Verifying Interactions
Use verify() to check that a method was called with specific arguments. You can also verify the number of calls or that it was never called.
Testing BLoC with Mocktail and blocTest
Combine Mocktail with blocTest to test BLoCs that depend on mocked services. The mock is created in the setUp or directly in the build function.
Working with Async Streams
When your BLoC listens to a stream from a dependency (e.g., a WebSocket or database listener), you can provide a mock stream and control its emissions during the test.
Capturing Arguments
Sometimes you need to capture the arguments passed to a mocked method to verify them later. Use captureAny or a custom ArgumentMatcher.
Resetting Mocks
To reset a mock's interactions and stubs between tests, you can create a new instance in setUp. Mocktail doesn't have a built‑in reset method, but recreating the mock is the simplest approach.
Mocking with Generic Types
Mocktail supports generic classes. Use Mock with the generic type or mock<T>().
Best Practices
- Create mocks in
setUp– Ensures a fresh mock for each test. - Use
any()for arguments you don't care about – Keeps stubs flexible. - Verify only essential interactions – Over‑verifying makes tests brittle.
- Use
argThatwith predicates – For complex argument matching. - Mock only dependencies, not the system under test – Your BLoC should be the real instance.
- Combine with
blocTest– It handles subscriptions and emissions automatically. - Keep mocks simple – Avoid stubbing unnecessary methods.
Common Mistakes
- ❌ Forgetting to stub a method – The mock returns
nullby default, which may causeNullerrors. ✅ Always stub methods that will be called. - ❌ Using
thenReturnwith a Future – Should usethenAnswerfor async. ✅ UsethenAnswerfor futures and streams. - ❌ Not resetting mocks – Stubs from previous tests can leak.
✅ Create new mocks in
setUpor usereset(). - ❌ Mixing Mocktail with Mockito – They use different syntax and can conflict. ✅ Stick to one mocking library.
- ❌ Stubbing methods with
any()but not matching the actual call – Verify that the arguments match your stub.
Conclusion
Mocktail provides a clean, code‑generation‑free way to mock dependencies for BLoC testing. By combining it with blocTest, you can write fast, reliable unit tests that verify your BLoC's behavior in isolation. Mastering Mocktail will significantly improve your testing workflow and code quality.