mocktail

$npx mdskill add evanca/flutter-ai-rules/mocktail

Generate realistic Dart mocks for Flutter tests without code generation.

  • Creates stubs for verifying interactions and registering fallback values.
  • Integrates with the mocktail package for runtime noSuchMethod mocking.
  • Decides between mocks, fakes, and real objects based on verification needs.
  • Delivers clear guidelines on when to use each mock type in tests.

SKILL.md

.github/skills/mocktailView on GitHub ↗
---
name: mocktail
description: Uses the Mocktail package for mocking in Flutter/Dart tests. Use when creating mocks, stubbing methods, verifying interactions, registering fallback values, or deciding between mocks, fakes, and real objects.
---

# Mocktail Skill

This skill defines how to correctly use the `mocktail` package for mocking in Dart and Flutter tests.

---

## 1. Mock vs. Fake vs. Real Object

| Use | When |
|---|---|
| **Real object** | Prefer over mocks when practical. |
| **Fake** (`extends Fake`) | Lightweight custom implementation; override only the methods you need. Prefer over mocks when you don't need interaction verification. |
| **Mock** (`extends Mock`) | Only when you need to **verify interactions** (call counts, arguments) or stub dynamic responses. |

- Never add `@override` methods or implementations to a class extending `Mock`.
- Only use mocks if your test has `verify` assertions; otherwise prefer real or fake objects.

---

## 2. Creating Mocks

```dart
class MockMyService extends Mock implements MyService {}
class FakeMyEvent extends Fake implements MyEvent {}
```

No code generation required — unlike Mockito, Mocktail uses `noSuchMethod` at runtime.

---

## 3. Registering Fallback Values

Register fallback values **before** using custom types with argument matchers. Do this in `setUpAll` or at the top of your test:

```dart
setUpAll(() {
  registerFallbackValue(FakeMyEvent());
});
```

- Required for non-nullable custom types used with `any()`, `captureAny()`, or `captureThat()`.
- Register fallback values for **any** custom type used with argument matchers.

---

## 4. Stubbing

```dart
final mock = MockMyService();

// Return a value
when(() => mock.fetchData()).thenReturn('result');

// Throw an error
when(() => mock.fetchData()).thenThrow(Exception('error'));

// Dynamic/async response
when(() => mock.fetchData()).thenAnswer((_) async => 'result');

// Future<void>
when(() => mock.doWork()).thenAnswer((_) async {});
```

- Always stub async methods (returning `Future` or `Future<void>`) with `thenAnswer`.
- Stub every method you expect to be called, even if it's not the focus of your test.

---

## 5. Named Parameters

Always include **all named parameters** in both `when` and `verify` calls. Use `any(named: 'paramName')` for those you don't care about:

```dart
when(() => mock.fetch(
  id: any(named: 'id'),
  headers: any(named: 'headers'),
)).thenReturn(response);
```

- If a method has default values for named parameters, Mocktail still expects them all to be matched.

---

## 6. Verification

```dart
verify(() => mock.fetchData());             // called at least once
verifyNever(() => mock.fetchData());        // never called
verify(() => mock.fetchData()).called(2);   // called exactly twice
```

---

## 7. Argument Matchers

```dart
// Any positional argument
when(() => mock.process(any())).thenReturn(true);

// Capture arguments for later assertions
final captured = verify(() => mock.process(captureAny())).captured;
print(captured.last);
```

- Use `any()` for positional parameters when you don't care about the exact value.
- Use `captureThat()` for conditional capturing.
- When matching string output, be aware of what `.toString()` returns for the type.

---

## References

- [Mocktail GitHub Repository](https://github.com/felangel/mocktail)

More from evanca/flutter-ai-rules

SkillDescription
architecture-feature-firstStructures Flutter apps using layered architecture (UI / Logic / Data) with feature-first file organization. Use when creating new features, designing the project structure, adding repositories/services/view models (or cubits/providers/notifiers), or wiring dependency injection. State management agnostic.
blocImplements Flutter state management using the bloc library (Bloc and Cubit). Use when creating new features, screens, or state management logic with bloc/cubit, modeling state, wiring Flutter widgets to blocs, or writing bloc/cubit unit tests.
dart-3-updatesApplies Dart 3 language features in Flutter/Dart code. Use when writing if-else or switch statements, creating new classes, or deciding between a data class and a record.
effective-dartApplies Effective Dart guidelines in Flutter/Dart code. Use when writing or reviewing Dart code for naming conventions, types, style, imports, file structure, usage patterns, documentation, testing, widgets, state management, or performance.
firebase-aiIntegrates Firebase AI Logic into Flutter apps. Use when setting up the firebase_ai plugin, calling Gemini models, handling AI service errors, or applying security and privacy considerations for AI features.
firebase-analyticsIntegrates Firebase Analytics into Flutter apps. Use when setting up analytics, logging events, setting user properties, or configuring event parameters.
firebase-app-checkIntegrates Firebase App Check into Flutter apps. Use when setting up App Check, selecting providers per platform, using debug providers during development, enabling enforcement, or applying App Check security best practices.
firebase-authIntegrates Firebase Authentication into Flutter apps. Use when setting up auth, managing auth state, implementing email/password or social sign-in, handling auth errors, managing users, or applying security best practices.
firebase-cloud-firestoreIntegrates Cloud Firestore into Flutter apps. Use when setting up Firestore, designing document/collection structure, reading and writing data, working with real-time listeners, designing for scale, or applying security rules.
firebase-cloud-functionsCalls Firebase Cloud Functions from Flutter apps. Use when setting up callable functions, passing data to functions, handling errors from function calls, optimizing performance, or testing with the Firebase Emulator Suite.