# Testing with package:test and Mocks — Dart

Source: https://www.skillbyai.com/en/dart/t-testing

> Write unit tests, async tests and tests with fakes or mocks.

## Fast, reliable tests

**`package:test`** is the standard testing library: write `test('description', () { ... })` functions grouped with `group`, use **`expect(actual, matcher)`** with matchers such as `equals`, `isTrue`, `contains`, `hasLength`, `throwsA(isA<StateError>())`, `closeTo` and `isNull`, and set up shared state with `setUp` and `tearDown`. Tests can be **`async`**: return a Future and `await` inside, or use `expectLater` with stream matchers such as `emitsInOrder`. Run with `dart test` (and `flutter test` in Flutter apps), filter with `--name`, and tag slow tests. Isolate code from dependencies by depending on **abstract classes** and passing **fakes** in tests (a `FakeGateway implements PaymentGateway`), or use **`mocktail`** (no code generation) or **`mockito`** (with generated mocks) for mocks with `when(...).thenAnswer(...)` and `verify(...)`. For time-based code, the **`fake_async`** package controls timers and microtasks. Measure coverage with `dart test --coverage` and format it with the `coverage` package. Flutter adds widget tests and integration tests on top of the same foundations.

## Unit tests with a fake and mocktail

Behaviour is checked without real network calls.

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

class MockGateway extends Mock implements PaymentGateway {}

void main() {
  group('PaymentService', () {
    late MockGateway gateway;
    late PaymentService service;

    setUp(() {
      gateway = MockGateway();
      service = PaymentService(gateway);
    });

    test('charges the order total once', () async {
      when(() => gateway.charge(any(), any())).thenAnswer((_) async => 'pay_1');

      final id = await service.pay(orderId: 'o-1', amountPaise: 49900);

      expect(id, equals('pay_1'));
      verify(() => gateway.charge('o-1', 49900)).called(1);
    });

    test('rejects non-positive amounts', () {
      expect(() => service.pay(orderId: 'o-2', amountPaise: 0), throwsA(isA<ArgumentError>()));
    });

    test('streams can be checked in order', () {
      expect(Stream.fromIterable([2, 1, 0]), emitsInOrder([2, 1, 0, emitsDone]));
    });
  });
}
```

## Fakes before mocks

A small hand-written fake (an in-memory repository, a gateway that records calls) is often clearer than many `when(...)` stubs, and it can be reused across tests.

**Quiz:** Which matcher checks that a function throws a specific error type in package:test?

- [ ] equals
- [ ] isNull
- [x] throwsA(isA<ArgumentError>())
- [ ] emitsDone

*Answer:* throwsA(isA<ArgumentError>()). throwsA with isA<T>() asserts the thrown object's type.
