mockito 5.4.5 copy "mockito: ^5.4.5" to clipboard
mockito: ^5.4.5 copied to clipboard

A mock framework inspired by Mockito with APIs for Fakes, Mocks, behavior verification, and stubbing.

example/example.dart

import 'dart:async';

import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';

import 'example.mocks.dart';

// Real class
class Cat {
  String? sound() => 'Meow';
  bool? eatFood(String? food, {bool? hungry}) => true;
  Future<void> chew() async => print('Chewing...');
  int? walk(List<String>? places) => 7;
  void sleep() {}
  void hunt(String? place, String? prey) {}
  int lives = 9;
}

// Fake class
class FakeCat extends Fake implements Cat {
  @override
  bool? eatFood(String? food, {bool? hungry}) {
    print('Fake eat $food');
    return true;
  }
}

abstract class Callbacks {
  Cat findCat(String name);
  String? makeSound();
}

@GenerateMocks([
  Cat,
  Callbacks,
], customMocks: [
  MockSpec<Cat>(
    as: #MockCatRelaxed,
    onMissingStub: OnMissingStub.returnDefault,
  ),
])
void main() {
  late Cat cat;

  setUp(() {
    // Create mock object.
    cat = MockCat();
  });

  test("Let's verify some behaviour!", () {
    // Stub a method before interacting with it.
    when(cat.sound()).thenReturn('Meow');

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

    // Verify the interaction.
    verify(cat.sound());
  });

  test('How about some stubbing?', () {
    // Unstubbed methods throw MissingStubError.
    expect(() => cat.sound(), throwsA(isA<MissingStubError>()));

    // Stub a method before interacting with it.
    when(cat.sound()).thenReturn('Purr');
    expect(cat.sound(), 'Purr');

    // You can call it again.
    expect(cat.sound(), 'Purr');

    // Let's change the stub.
    when(cat.sound()).thenReturn('Meow');
    expect(cat.sound(), 'Meow');

    // You can stub getters.
    when(cat.lives).thenReturn(9);
    expect(cat.lives, 9);

    // You can stub a method to throw.
    when(cat.lives).thenThrow(RangeError('Boo'));
    expect(() => cat.lives, throwsRangeError);

    // We can calculate a response at call time.
    final responses = ['Purr', 'Meow'];
    when(cat.sound()).thenAnswer((_) => responses.removeAt(0));
    expect(cat.sound(), 'Purr');
    expect(cat.sound(), 'Meow');
  });

  test('Argument matchers', () {
    // You can use `any`
    when(cat.eatFood(any)).thenReturn(false);

    // ... or plain arguments themselves
    when(cat.eatFood('fish')).thenReturn(true);

    // ... including collections
    when(cat.walk(['roof', 'tree'])).thenReturn(2);

    // ... or matchers
    when(cat.eatFood(argThat(startsWith('dry')))).thenReturn(false);

    // ... or mix arguments with matchers
    when(cat.eatFood(argThat(startsWith('dry')), hungry: true))
        .thenReturn(true);
    expect(cat.eatFood('fish'), isTrue);
    expect(cat.walk(['roof', 'tree']), equals(2));
    expect(cat.eatFood('dry food'), isFalse);
    expect(cat.eatFood('dry food', hungry: true), isTrue);

    // You can also verify using an argument matcher.
    verify(cat.eatFood('fish'));
    verify(cat.walk(['roof', 'tree']));
    verify(cat.eatFood(argThat(contains('food'))));

    // You can verify setters.
    cat.lives = 9;
    verify(cat.lives = 9);

    cat.hunt('backyard', null);
    verify(cat.hunt('backyard', null)); // OK: no arg matchers.

    cat.hunt('backyard', null);
    verify(cat.hunt(argThat(contains('yard')),
        argThat(isNull))); // OK: null is wrapped in an arg matcher.
  });

  test('Named arguments', () {
    // GOOD: argument matchers include their names.
    when(cat.eatFood(any, hungry: anyNamed('hungry'))).thenReturn(true);
    when(cat.eatFood(any, hungry: argThat(isNotNull, named: 'hungry')))
        .thenReturn(false);
    when(cat.eatFood(any, hungry: captureAnyNamed('hungry'))).thenReturn(false);
    when(cat.eatFood(any, hungry: captureThat(isNotNull, named: 'hungry')))
        .thenReturn(true);
  });

  test('Verifying exact number of invocations / at least x / never', () {
    when(cat.sound()).thenReturn('Meow');

    cat.sound();
    cat.sound();
    // Exact number of invocations
    verify(cat.sound()).called(2);

    cat.sound();
    cat.sound();
    cat.sound();
    // Or using matcher
    verify(cat.sound()).called(greaterThan(1));

    // Or never called
    verifyNever(cat.eatFood(any));
  });

  test('Verification in order', () {
    when(cat.sound()).thenReturn('Meow');
    when(cat.eatFood(any)).thenReturn(true);

    cat.eatFood('Milk');
    cat.sound();
    cat.eatFood('Fish');
    verifyInOrder([cat.eatFood('Milk'), cat.sound(), cat.eatFood('Fish')]);
  });

  test('Making sure interaction(s) never happened on mock', () {
    verifyZeroInteractions(cat);
  });

  test('Finding redundant invocations', () {
    when(cat.sound()).thenReturn('Meow');

    cat.sound();
    verify(cat.sound());
    verifyNoMoreInteractions(cat);
  });

  test('Capturing arguments for further assertions', () {
    when(cat.eatFood(any)).thenReturn(true);

    // Simple capture:
    cat.eatFood('Fish');
    expect(verify(cat.eatFood(captureAny)).captured.single, 'Fish');

    // Capture multiple calls:
    cat.eatFood('Milk');
    cat.eatFood('Fish');
    expect(verify(cat.eatFood(captureAny)).captured, ['Milk', 'Fish']);

    // Conditional capture:
    cat.eatFood('Milk');
    cat.eatFood('Fish');
    expect(
        verify(cat.eatFood(captureThat(startsWith('F')))).captured, ['Fish']);
  });

  test('Waiting for an interaction', () async {
    when(cat.eatFood(any)).thenReturn(true);

    Future<void> chewHelper(Cat cat) {
      return cat.chew();
    }

    // Waiting for a call.
    unawaited(chewHelper(cat));
    await untilCalled(cat.chew()); // This completes when cat.chew() is called.

    // Waiting for a call that has already happened.
    cat.eatFood('Fish');
    await untilCalled(cat.eatFood(any)); // This completes immediately.
  });

  test('Mocked callbacks', () {
    final makeSoundCallback = MockCallbacks().makeSound;
    when(makeSoundCallback()).thenReturn('woof');
    expect(makeSoundCallback(), 'woof');

    final findCatCallback = MockCallbacks().findCat;
    final mockCat = MockCat();
    when(findCatCallback('Pete')).thenReturn(mockCat);
    when(mockCat.sound()).thenReturn('meow');
    expect(findCatCallback('Pete').sound(), 'meow');
  });

  test('Fake class', () {
    // Create a new fake Cat at runtime.
    final cat = FakeCat();

    cat.eatFood('Milk'); // Prints 'Fake eat Milk'.
    expect(() => cat.sleep(), throwsUnimplementedError);
  });

  test('Relaxed mock class', () {
    // Create a new mock Cat at runtime.
    final cat = MockCatRelaxed();

    // You can call it without stubbing.
    cat.sleep();

    // Non-null properties and function return values
    // default to reasonable defaults.
    expect(cat.lives, 0);

    // Nullable properties and function return values
    // default to null unless you stub them.
    expect(cat.sound(), null);
    expect(cat.eatFood('Milk'), null);

    verify(cat.sleep());
  });
}
1.39k
likes
160
points
1.1M
downloads

Publisher

verified publisherdart.dev

Weekly Downloads

A mock framework inspired by Mockito with APIs for Fakes, Mocks, behavior verification, and stubbing.

Repository (GitHub)
View/report issues
Contributing

Topics

#testing #mocking

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

analyzer, build, code_builder, collection, dart_style, matcher, meta, path, source_gen, test_api

More

Packages that depend on mockito