0
0
Fluttermobile~15 mins

Mock dependencies in Flutter - Deep Dive

Choose your learning style9 modes available
Overview - Mock dependencies
What is it?
Mock dependencies are fake versions of parts of your app used during testing. They imitate real components like services or databases but with simple, controlled behavior. This helps you test your app's parts without relying on real external systems. It makes testing faster, safer, and more focused.
Why it matters
Without mock dependencies, tests would depend on real services that might be slow, unreliable, or change data unexpectedly. This would make tests flaky and hard to trust. Mocking lets you isolate the part you want to test, so you can find bugs quickly and confidently. It also helps when real services are not ready or costly to use.
Where it fits
Before learning mock dependencies, you should understand basic Flutter testing and how your app uses external services. After this, you can learn about advanced testing techniques like integration tests and continuous integration setups.
Mental Model
Core Idea
Mock dependencies are stand-ins that behave like real parts but let you control and observe interactions during tests.
Think of it like...
Imagine testing a car's radio without the engine running. You replace the engine with a simple motor that just spins at a fixed speed. This lets you focus on the radio without worrying about the engine's complexity or failures.
┌───────────────┐     uses     ┌───────────────┐
│  Your Widget  │────────────▶│  Dependency   │
└───────────────┘             └───────────────┘
         ▲                            ▲
         │                            │
         │                            │
         │ replaces with mock         │
         │                            │
┌───────────────┐             ┌───────────────┐
│  Test Code    │────────────▶│  Mock Object  │
└───────────────┘             └───────────────┘
Build-Up - 7 Steps
1
FoundationWhat are dependencies in Flutter
🤔
Concept: Understand what dependencies are and why your app uses them.
Dependencies are parts your app needs to work, like a service fetching data or a database saving info. Your widgets or classes call these dependencies to do tasks. For example, a weather app depends on a weather API service to get data.
Result
You know that dependencies are external parts your app relies on to function.
Understanding dependencies helps you see why controlling them matters during testing.
2
FoundationWhy test with fake parts
🤔
Concept: Learn why using real dependencies in tests can cause problems.
Real dependencies might be slow, unreliable, or change data. Tests using them can fail randomly or take too long. Using fake parts, or mocks, lets you control behavior and make tests fast and reliable.
Result
You realize that fake parts make tests more stable and focused.
Knowing the limits of real dependencies in tests motivates using mocks.
3
IntermediateCreating a simple mock class
🤔Before reading on: do you think a mock class needs to implement all methods of the real class or just the ones used in tests? Commit to your answer.
Concept: Learn how to write a basic mock class that imitates a real dependency.
In Flutter, you create a mock by making a class that implements the same interface as the real dependency. You override methods to return fixed data or track calls. For example, a mock service returns preset data instead of calling the network.
Result
You can create a mock that replaces a real service in tests.
Understanding that mocks only need to cover used methods keeps tests simple and focused.
4
IntermediateUsing mockito package for mocks
🤔Before reading on: do you think mockito generates mocks automatically or requires manual coding for each mock? Commit to your answer.
Concept: Learn to use the popular mockito package to create mocks easily.
Mockito is a Flutter package that generates mock classes automatically from your interfaces. You write less code and get features like verifying method calls and setting return values. This speeds up writing tests and reduces errors.
Result
You can quickly create and use mocks with mockito in your tests.
Knowing about mockito saves time and improves test quality by automating mock creation.
5
IntermediateInjecting mocks into widgets
🤔Before reading on: do you think you can replace dependencies inside widgets directly or do you need a pattern like dependency injection? Commit to your answer.
Concept: Learn how to provide mocks to widgets during tests using dependency injection.
Widgets often get dependencies via constructors or providers. In tests, you pass mocks instead of real dependencies. For example, if a widget needs a service, you give it a mock service when building it in the test.
Result
Your widget uses the mock dependency during tests, isolating its behavior.
Understanding dependency injection is key to swapping real parts with mocks in tests.
6
AdvancedVerifying interactions with mocks
🤔Before reading on: do you think tests should only check outputs or also how dependencies were used? Commit to your answer.
Concept: Learn to check if your code called the mock dependency correctly.
Mockito lets you verify if certain methods were called on mocks, how many times, and with what arguments. This helps ensure your code interacts with dependencies as expected, not just produces correct outputs.
Result
Tests can confirm both results and correct usage of dependencies.
Knowing how to verify interactions catches bugs that output checks alone miss.
7
ExpertMocking asynchronous dependencies safely
🤔Before reading on: do you think mocking async calls is the same as sync calls? Commit to your answer.
Concept: Learn the challenges and best practices for mocking async dependencies in Flutter.
Many dependencies use async methods returning Futures or Streams. Mocks must return matching async types to avoid errors. Also, controlling timing and errors in async mocks helps test edge cases like delays or failures.
Result
You can write robust tests that handle async dependencies correctly.
Understanding async mocking prevents subtle bugs and flaky tests in real-world apps.
Under the Hood
Mocks work by replacing real objects with fake ones that have the same interface. When your code calls a mock, it runs the mock's methods instead of the real ones. Testing frameworks like mockito generate these fake classes dynamically or via code generation. They also track calls and arguments internally to support verification.
Why designed this way?
Mocks were designed to isolate units of code during testing, avoiding dependencies on slow or unreliable external systems. Early testing was brittle because it used real services. Mocking evolved to provide controlled, repeatable environments. Tools like mockito automate mock creation to reduce manual errors and boilerplate.
┌───────────────┐       calls       ┌───────────────┐
│  Test Code    │──────────────────▶│  Mock Object  │
└───────────────┘                   └───────────────┘
         │                                  │
         │ verifies calls                   │ returns preset data
         │◀─────────────────────────────────│
         │                                  │
┌───────────────┐                   ┌───────────────┐
│  Verification │                   │  Call Tracker │
└───────────────┘                   └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: do you think mocks run the real code of dependencies? Commit yes or no.
Common Belief:Mocks run the real code but just look like fakes.
Tap to reveal reality
Reality:Mocks do NOT run real code; they simulate behavior with custom code.
Why it matters:If you expect mocks to run real code, tests may pass incorrectly or hide bugs.
Quick: do you think mocks always make tests slower? Commit yes or no.
Common Belief:Mocks slow down tests because they add extra layers.
Tap to reveal reality
Reality:Mocks usually make tests faster by avoiding real network or database calls.
Why it matters:Believing mocks slow tests may discourage their use, leading to fragile slow tests.
Quick: do you think you must mock every method of a dependency? Commit yes or no.
Common Belief:You must mock all methods of a dependency to avoid errors.
Tap to reveal reality
Reality:You only need to mock methods your test actually uses.
Why it matters:Mocking unnecessary methods wastes time and complicates tests.
Quick: do you think mocks can replace integration tests completely? Commit yes or no.
Common Belief:Mocks can replace all other types of tests.
Tap to reveal reality
Reality:Mocks are for unit tests; integration tests still need real dependencies.
Why it matters:Overusing mocks can miss bugs that only appear with real systems.
Expert Zone
1
Mocks can be stateful or stateless; knowing when to keep state in mocks avoids unrealistic tests.
2
Over-mocking can hide design problems; sometimes refactoring dependencies is better than mocking complex behavior.
3
Mockito's generated mocks use Dart's noSuchMethod, which can cause confusing errors if interfaces change.
When NOT to use
Avoid mocks when testing full app flows or UI integration; use real services or test doubles like fakes or stubs instead. For performance testing, mocks may give unrealistic results.
Production Patterns
In production, mocks are used in unit tests to isolate logic. Dependency injection frameworks help swap mocks easily. Teams often combine mocks with real service tests in CI pipelines to balance speed and coverage.
Connections
Dependency Injection
Mocks rely on dependency injection to replace real parts with fakes during tests.
Understanding dependency injection helps you swap dependencies easily, making mocking practical and clean.
Test-Driven Development (TDD)
Mocking supports TDD by letting you write tests before real dependencies exist.
Knowing mocks enables faster TDD cycles by isolating units and simulating missing parts.
Theater Acting
Mocks are like actors playing roles of real people in a play to test scenes without the real cast.
Seeing mocks as actors helps appreciate their role in simulating behavior and interactions.
Common Pitfalls
#1Mock returns wrong type causing test crash
Wrong approach:when(mockService.fetchData()).thenReturn('string instead of expected object');
Correct approach:when(mockService.fetchData()).thenAnswer((_) async => expectedObject);
Root cause:Not matching the expected return type or async nature of the method.
#2Not injecting mock, test uses real dependency
Wrong approach:final widget = MyWidget(); // no mock passed await tester.pumpWidget(widget);
Correct approach:final widget = MyWidget(service: mockService); await tester.pumpWidget(widget);
Root cause:Forgetting to provide the mock dependency to the widget under test.
#3Verifying method never called but test passes
Wrong approach:verifyNever(mockService.fetchData()); // but fetchData was called // test still passes due to missing verify call
Correct approach:verifyNever(mockService.fetchData()); // test fails if fetchData called // ensures correct verification
Root cause:Misusing verification or missing verification step in test.
Key Takeaways
Mock dependencies let you test parts of your app in isolation by replacing real components with controllable fakes.
Using mocks makes tests faster, more reliable, and easier to write by avoiding real network or database calls.
Dependency injection is essential to swap real dependencies with mocks during testing.
Mockito is a powerful tool that automates mock creation and verification in Flutter tests.
Proper async mocking and verification of interactions help catch subtle bugs and ensure your code uses dependencies correctly.