# mocktail 1.0.5

A Dart mock library which simplifies mocking with null safety support and no manual mocks or code generation.




## Installing
```
export PUB_HOSTED_URL=https://pub.mirror.p-hatan.com
flutter pub add mocktail
```
Published: 2026-04-10T04:16:05.020857Z
Expected archive SHA-256: 5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa

Available in cache; verification: upstream_checksum
## Direct dependencies
- collection: ^1.15.0
- matcher: ^0.12.15
- test_api: >=0.2.1 <0.8.0

## Package README (untrusted upstream documentation)
# 🍹 mocktail

[![Pub](https://img.shields.io/pub/v/mocktail.svg)](https://pub.dev/packages/mocktail)
[![mocktail](https://github.com/felangel/mocktail/actions/workflows/mocktail.yaml/badge.svg)](https://github.com/felangel/mocktail/actions)
[![coverage](https://raw.githubusercontent.com/felangel/mocktail/main/coverage_badge.svg)](https://github.com/felangel/mocktail/actions)
[![License: MIT](https://img.shields.io/badge/license-MIT-purple.svg)](https://opensource.org/licenses/MIT)

---

Mock library for Dart inspired by [mockito](https://pub.dev/packages/mockito).

Mocktail focuses on providing a familiar, simple API for creating mocks in Dart (with null-safety) without the need for manual mocks or code generation.

## Creating a Mock

```dart
import 'package:mocktail/mocktail.dart';

// A Real Cat class
class Cat {
  String sound() => 'meow!';
  bool likes(String food, {bool isHungry = false}) => false;
  final int lives = 9;
}

// A Mock Cat class
class MockCat extends Mock implements Cat {}

void main() {
  // Create a Mock Cat instance
  final cat = MockCat();
}
```

## Stub and Verify Behavior

The `MockCat` instance can then be used to stub and verify calls.

```dart
// Stub the `sound` method.
when(() => cat.sound()).thenReturn('meow');

// Verify no interactions have occurred.
verifyNever(() => cat.sound());

// Interact with the mock cat instance.
cat.sound();

// Verify the interaction occurred.
verify(() => cat.sound()).called(1);

// When mocktail verifies an invocation, it is then excluded from further verifications.
verifyNever(() => cat.sound());

// Interact with the mock instance again.
cat.sound();

// The verification count is 1 since there was only 1 invocation since the last verification.
verify(() => cat.sound()).called(1);
```

## Additional Usage

```dart
// Stub a method before interacting with the mock.
when(() => cat.sound()).thenReturn('purrr!');
expect(cat.sound(), 'purrr!');

// You can interact with the mock multiple times.
expect(cat.sound(), 'purrr!');

// You can change the stub.
when(() => cat.sound()).thenReturn('meow!');
expect(cat.sound(), 'meow');

// You can stub getters.
when(() => cat.lives).thenReturn(10);
expect(cat.lives, 10);

// You can stub a method for specific arguments.
when(() => cat.likes('fish', isHungry: false)).thenReturn(true);
expect(cat.likes('fish', isHungry: false), isTrue);

// You can verify the interaction for specific arguments.
verify(() => cat.likes('fish', isHungry: false)).called(1);

// Or alternatively use any(that: ...) to use a matcher.
verify(() => cat.likes(any(that: isA<String>().having((food) => food, 'name', 'fish')))).called(1);

// You can stub a method using argument matcher: `any`.
// When stubbing a positional argument, use `any()`.
// When stubbing a named argument, use `any(named: '<argName>`)`.
// A custom matcher can be provided using `any(that: customMatcher)`.
when(() => cat.likes(any(), isHungry: any(named: 'isHungry', that: isFalse)).thenReturn(true);
expect(cat.likes('fish', isHungry: false), isTrue);

// You can stub a method to throw.
when(() => cat.sound()).thenThrow(Exception('oops'));
expect(() => cat.sound(), throwsA(isA<Exception>()));

// You can calculate stubs dynamically.
final sounds = ['purrr', 'meow'];
when(() => cat.sound()).thenAnswer((_) => sounds.removeAt(0));
expect(cat.sound(), 'purrr');
expect(cat.sound(), 'meow');

// You can capture any argument.
when(() => cat.likes('fish')).thenReturn(true);
expect(cat.likes('fish'), isTrue);
final captured = verify(() => cat.likes(captureAny())).captured;
expect(captured.last, equals(['fish']));

// You can capture a specific argument based on a matcher.
when(() => cat.likes(any())).thenReturn(true);
expect(cat.likes('fish'), isTrue);
expect(cat.likes('dog food'), isTrue);
final captured = verify(() => cat.likes(captureAny(that: startsWith('d')))).captured;
expect(captured.last, equals(['dog food']));
```

## Resetting Mocks

```dart
reset(cat); // Reset stubs and interactions
```

## How it works

Mocktail uses closures to handle catching `TypeError` instances which would otherwise propagate and cause test failures when stubbing/verifying non-nullable return types. Check out [#24](https://github.com/felangel/mocktail/issues/24) for more information.

In order to support argument matchers such as `any` and `captureAny` mocktail has to register default fallback values to return when the argument matchers are used. Out of the box, it automatically handles all primitive types, however, when using argument matchers in place of custom types developers must use `registerFallbackValue` to provide a default return value. It is only required to call `registerFallbackValue` once per type so it is recommended to place all `registerFallbackValue` calls within `setUpAll`.

```dart
class Food {...}

class Cat {
  bool likes(Food food) {...}
}

...

class MockCat extends Mock implements Cat {}

class FakeFood extends Fake implements Food {}

void main() {
  setUpAll(() {
    registerFallbackValue(FakeFood());
  });

  test('...', () {
    final cat = MockCat();
    when(() => cat.likes(any()).thenReturn(true);
    ...
  });
}
```

## FAQs

#### Why am I getting an invalid_implementation_override error when trying to Fake certain classes like ThemeData and ColorScheme?

[Relevant Issue](https://github.com/felangel/mocktail/issues/59)

This is likely due to differences in the function signature of `toString` for the class and can be resolved
using a mixin as demonstrated below:

```dart
mixin DiagnosticableToStringMixin on Object {
  @override
  String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
    return super.toString();
  }
}

class FakeThemeData extends Fake
  with DiagnosticableToStringMixin
  implements ThemeData {}
```

#### Why can't I stub/verify extension methods properly?

[Relevant Issue](https://github.com/felangel/mocktail/issues/58)

Extension methods cannot be stubbed/verified as they are treated like static methods. This means that calls go directly to the extension method without caring about the instance. As a result, stubs and verify calls to extensions always result in an invocation of the real extension method.

Instead of stubbing/verifying extension methods directly, prefer to stub/verify public members on the instance with which the extension methods interact.

#### Why am I seeing error: type 'Null' is not a subtype of type 'Future<void>'?

[Relevant Issue](https://github.com/felangel/mocktail/issues/78)

By default when a class extends `Mock` any unstubbed methods return `null`.

For example, take the following class:

```dart
class Person {
  Future<void> sleep() {
    await Future<void>.delayed(Duration(hours: 8));
  }
}
```

We can create a `MockPerson` like:

```dart
class MockPerson extends Mock implements Person {}
```

If we have code that invokes `sleep` on `MockPerson` we will get a `TypeError`:

```sh
type 'Null' is not a subtype of type 'Future<void>'
```

This is because we did not stub `sleep` so when `sleep` is called on an instance of `MockPerson`, `mocktail` returns `null` which is not compatible with `Future<void>`.

To address this, we must explicitly stub `sleep` like:

```dart
final person = MockPerson();
when(() => person.sleep()).thenAnswer((_) async {});
```

#### Why is my method throwing a `TypeError` when stubbing using `any()`?

[Relevant Issue](https://github.com/felangel/mocktail/issues/162)

By default when a class extends `Mock` any unstubbed methods return `null`. When stubbing using `any()` the type must be inferable. However, when a method has a generic type argument it might not be able to infer the type and as a result, the generic would fallback to `dynamic` causing the method to act as if it was unstubbed.

For example, take the following class and its method:

```dart
class Cache {
  bool set<T>(String key, T value) {
    return true;
  }
}
```

The following stub will be equivalent to calling `set<dynamic>(...)`:

```dart
// The type `T` of `any<T>()` is inferred to be `dynamic`.
when(() => cache.set(any(), any())).thenReturn((_) => true);
```

To address this, we must explicitly stub `set` with a type:

```dart
final cache = MockCache();
when(() => cache.set<int>(any(), any())).thenReturn((_) => true);
cache.set<int>('key', 1);
verify(() => cache.set<int>(any(), any())).called(1);
```

The type doesn't need to be applied to `set<T>()`, any explicit type that allows `any<T>()` infer its type will allow the method to be stubbed for that type:

```dart
when(() => cache.set(any(), any<int>())).thenReturn((_) => true);
```

## Migrating from Mockito

Mocktail's API is very similar to Mockito making the migration as smooth as possible.

The key differences are:

1. **No code generation** — remove `@GenerateMocks`, `build_runner`, and generated `.mocks.dart` files.
1. **Wrap calls in closures** — stub and verify with `() => mock.method()` instead of `mock.method()`
1. **Unified matchers** — `any()`, `any(named:)`, `any(that:)` replace `anyString`, `anyInt`, `argThat`, etc.

### Quick Reference

| `mockito`                                       | `mocktail`                                              |
| ----------------------------------------------- | ------------------------------------------------------- |
| `@GenerateMocks([Cat])` + `build_runner`        | `class MockCat extends Mock implements Cat {}`          |
| `MockitoAnnotations.initMocks(this)`            | _(not needed)_                                          |
| `when(mock.sound()).thenReturn('meow')`         | `when(() => mock.sound()).thenReturn('meow')`           |
| `when(mock.sound()).thenAnswer((_) => 'purr')`  | `when(() => mock.sound()).thenAnswer((_) => 'purr')`    |
| `when(mock.sound()).thenThrow(Exception())`     | `when(() => mock.sound()).thenThrow(Exception())`       |
| `when(mock.fetch(any()))`                       | `when(() => mock.fetch(any()))`                         |
| `when(mock.fetch(anyNamed('url')))`             | `when(() => mock.fetch(any(named: 'url')))`             |
| `when(mock.fetch(argThat(startsWith('http'))))` | `when(() => mock.fetch(any(that: startsWith('http'))))` |
| `verify(mock.sound()).called(1)`                | `verify(() => mock.sound()).called(1)`                  |
| `verifyNever(mock.sound())`                     | `verifyNever(() => mock.sound())`                       |
| `verifyInOrder([mock.a(), mock.b()])`           | `verifyInOrder([() => mock.a(), () => mock.b()])`       |
| `verify(mock.fetch(captureAny)).captured`       | `verify(() => mock.fetch(captureAny())).captured`       |
| `verify(mock.fetch(captureThat(isNotNull)))`    | `verify(() => mock.fetch(captureAny(that: isNotNull)))` |
| `reset(mock)`                                   | `reset(mock)`                                           |
| `resetMockitoState()`                           | `resetMocktailState()`                                  |

### Sample Migration

**Before (mockito)**

```dart
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'cat_test.mocks.dart';

@GenerateMocks([Cat])
void main() {
  test('sounds', () {
    final Cat cat = MockCat();
    when(cat.sound()).thenReturn('meow');
    expect(cat.sound(), 'meow');
    verify(cat.sound()).called(1);
  });

  test('eat with matcher', () {
    final Cat cat = MockCat();
    when(cat.eat(argThat(startsWith('fish')))).thenAnswer((_) async => 'yum');
    expect(cat.eat('fishy'), completion(equals('yum')));
    verify(cat.eat('fishy')).called(1);
  });
}
```

**After (mocktail)**

```dart
import 'package:mocktail/mocktail.dart';

class MockCat extends Mock implements Cat {}

void main() {
  test('sounds', () {
    final Cat cat = MockCat();
    when(() => cat.sound()).thenReturn('meow');
    expect(cat.sound(), 'meow');
    verify(() => cat.sound()).called(1);
  });

  test('eat with matcher', () {
    final Cat cat = MockCat();
    when(() => cat.eat(any(that: startsWith('fish')))).thenAnswer((_) async => 'yum');
    expect(cat.eat('fishy'), completion(equals('yum')));
    verify(() => cat.eat('fishy')).called(1);
  });
}
```

## Changelog
# 1.0.5

- chore: minor improvements to example ([#266](https://github.com/felangel/mocktail/issues/266))
- docs: add mockito migration guide ([#265](https://github.com/felangel/mocktail/issues/265))
- chore: remove a stray override annotation ([#261](https://github.com/felangel/mocktail/issues/261))
- chore: add `funding` to `pubspec.yaml` ([#246](https://github.com/felangel/mocktail/issues/246))

# 1.0.4

- refactor: upgrade `analysis_options.yaml` ([#242](https://github.com/felangel/mocktail/issues/242))
- chore: fix minor typo in `CHANGELOG.md`

# 1.0.3

- docs: update ` README.md` to include `any(that: ...)` ([#226](https://github.com/felangel/mocktail/issues/226))
- chore: update LICENSE year
- chore: remove deprecated lint rules

# 1.0.2

- chore(deps): allow pkg:test_api >=0.7.0 ([#220](https://github.com/felangel/mocktail/issues/220))
- docs: update `verify` example in `README.md` ([#215](https://github.com/felangel/mocktail/issues/215))

# 1.0.1

- chore(deps): replace dependency on `package:test` with `package:test_api` to resolve version resolution issues with `pkg:analyzer`, `pkg:test`, and `flutter_test` ([#209](https://github.com/felangel/mocktail/issues/209))
- chore(deps): upgrade to `package:matcher` ^0.12.15

# 1.0.0

- refactor: use more strict analysis options ([#203](https://github.com/felangel/mocktail/issues/203))
- docs: adjust `LICENSE` year
- docs: add topics to `pubspec.yaml`

# 0.3.0

- **BREAKING** feat: add support for type argument matching ([#66](https://github.com/felangel/mocktail/issues/66))
- feat: improve verifyNoMoreInteractions failure message ([#118](https://github.com/felangel/mocktail/issues/118))
- docs: improve argument matcher documentation in `README` ([#102](https://github.com/felangel/mocktail/pull/102))
- docs: fix typo in \_registerMatcher inline docs ([#101](https://github.com/felangel/mocktail/pull/101))
- docs: minor snippet fixes in `README` ([#94](https://github.com/felangel/mocktail/pull/94))
- docs: enhance example to illustrate more use cases

# 0.3.0-dev.1

- **BREAKING** feat: add support for type argument matching ([#66](https://github.com/felangel/mocktail/issues/66))
- docs: minor snippet fixes in `README` ([#94](https://github.com/felangel/mocktail/pull/94))
- docs: enhance example to illustrate more use cases

# 0.2.0

- **BREAKING** refactor: remove generic from `registerFallbackValue`
- docs: add FAQs to README

# 0.1.4

- fix: add built-in fallback for `DateTime`

# 0.1.3

- docs: improve documentation regarding `registerFallbackValue` and how the library works
- tests: add additional tests for asyncVoid stubbing and verification

# 0.1.2

- feat: improve generic fallback support
- feat: improve error message for missing `registerFallbackValue`

# 0.1.1

- fix: add missing fallback value ([#34](https://github.com/felangel/mocktail/pull/34))
- docs: fix broken link in API documentation ([#33](https://github.com/felangel/mocktail/pull/33))

# 0.1.0

- feat: add `Mock.throwOnMissingStub()`
- fix: make `Mock` instances immutable
- chore: convert to `test: ^1.16.0`

# 0.0.2-dev.6

- fix: typo in matcher registration (`setUpAll`)
- chore: upgrade to `test_api: ^0.3.0`

# 0.0.2-dev.5

- fix: `verify` should use arg matcher from invocation if a matcher wasn't provided

# 0.0.2-dev.4

- **BREAKING** fix: `verifyInOrder` handles multiple method invocation verifications
- test: 100% coverage
- docs: additional inline API documentation updates

# 0.0.2-dev.3

- **BREAKING** fix: `verifyInOrder` function signature
- docs: update inline API documentation
- test: add nnbd compat tests

# 0.0.2-dev.2

- chore: documentation updates

# 0.0.2-dev.1

- **BREAKING** refactor: removed the `of` parameter of matchers in exchange for a `registerFallbackValue`

# 0.0.2-dev.0

- **BREAKING** refactor: revamp `mocktail` API to be typesafe instead of relying on `Symbol`

# 0.0.1-dev.12

- fix: any matcher with no value

# 0.0.1-dev.11

- chore: bump dependencies
  - `matcher: ^0.12.10`
  - `test: ^1.16.0`

# 0.0.1-dev.10

- feat: `thenReturn` argument is optional for `VoidCallback` returns
  - `when(cat).calls(#makeSound).thenReturn()`
- feat: add support for `captured` with `captureAny` and `captureAnyThat` matchers
- fix: verify fixes for default arguments (named and positional)

# 0.0.1-dev.9

- fix: call verification count per specific real invocation

# 0.0.1-dev.8

- fix: throw `NoSuchMethodError` when arguments match but memberName does not

# 0.0.1-dev.7

- **BREAKING** refactor: rename `verify(mock).calls(#member)` to `verify(mock).called(#member)`
- feat: add `any` argument matcher support to `verify` and `calls`
- feat: add `anyThat` argument matcher support to `verify` and `calls`
- feat: support `verify(mock).called(#member).once()`
- feat: support `verify(mock).called(#member).never()`
- feat: improve error messages to include invocation arguments

# 0.0.1-dev.6

- **BREAKING** refactor: use `Symbol` rather than `String`
- fix: strict argument matching on verification when arguments are provided

# 0.0.1-dev.5

- fix: override `toString` on `MocktailFailure` to improve visibility of failure messages

# 0.0.1-dev.4

- feat: add `Matcher` support to verify times API
- docs: minor usage documentation updates in README

# 0.0.1-dev.3

- **BREAKING** refactor: rename `positionalArgs` to `positionalArguments`
- **BREAKING** refactor: rename `namedArgs` to `namedArguments`
- fix: `thenAnswer` callback contains correct `Invocation`
- docs: minor documentation updates

# 0.0.1-dev.2

- docs: minor updates to README
- docs: minor updates to example

# 0.0.1-dev.1

- feat: initial release 🎉







 
