Skip to content

Commit

Permalink
fix(mocktail)!: verifyInOrder
Browse files Browse the repository at this point in the history
  • Loading branch information
felangel committed Mar 8, 2021
1 parent 936a018 commit 99ea9f8
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 94 deletions.
6 changes: 6 additions & 0 deletions packages/mocktail/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 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
Expand Down
3 changes: 2 additions & 1 deletion packages/mocktail/lib/mocktail.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
library mocktail;

export 'src/fake.dart';
// ignore: deprecated_member_use
export 'package:test_api/fake.dart' show Fake;
export 'src/mocktail.dart'
show
Mock,
Expand Down
50 changes: 0 additions & 50 deletions packages/mocktail/lib/src/fake.dart

This file was deleted.

61 changes: 33 additions & 28 deletions packages/mocktail/lib/src/mocktail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import 'dart:async';

import 'package:collection/collection.dart';
import 'package:matcher/matcher.dart';
import 'package:mocktail/mocktail.dart';
// ignore: deprecated_member_use
import 'package:test_api/test_api.dart';

import 'fake.dart';

part '_arg_matcher.dart';
part '_invocation_matcher.dart';
part '_is_invocation.dart';
Expand Down Expand Up @@ -47,26 +46,26 @@ void throwOnMissingStub(
/// customized at runtime to define how it may behave using [when].
///
/// __Example use__:
/// ```dart
/// // Real class.
/// class Cat {
/// String getSound(String suffix) => 'Meow$suffix';
/// }
///
/// // Real class.
/// class Cat {
/// String getSound(String suffix) => 'Meow$suffix';
/// }
///
/// // Mock class.
/// class MockCat extends Mock implements Cat {}
///
/// void main() {
/// // Create a new mocked Cat at runtime.
/// final cat = MockCat();
/// // Mock class.
/// class MockCat extends Mock implements Cat {}
///
/// // When 'getSound' is called, return 'Woof'
/// when(() => cat.getSound(any())).thenReturn('Woof');
/// void main() {
/// // Create a new mocked Cat at runtime.
/// final cat = MockCat();
///
/// // Try making a Cat sound...
/// print(cat.getSound('foo')); // Prints 'Woof'
/// }
/// // When 'getSound' is called, return 'Woof'
/// when(() => cat.getSound(any())).thenReturn('Woof');
///
/// // Try making a Cat sound...
/// print(cat.getSound('foo')); // Prints 'Woof'
/// }
/// ```
/// A class which `extends Mock` should not have any directly implemented
/// overridden fields or methods. These fields would not be usable as a [Mock]
/// with [verify] or [when]. To implement a subset of an interface manually use
Expand Down Expand Up @@ -173,7 +172,7 @@ typedef _ReturnsCannedResponse = Expectation<dynamic> Function();
/// canned response method on the result. For example:
///
/// ```dart
/// when(cat.eatFood("fish")).thenReturn(true);
/// when(() => cat.eatFood("fish")).thenReturn(true);
/// ```
///
/// Mocktail will store the fake call to `cat.eatFood`, and pair the exact
Expand Down Expand Up @@ -295,16 +294,16 @@ class Expectation<T> {
///
/// ```dart
/// cat.eatFood("chicken");
/// verify(cat.eatFood("fish"));
/// verify(() => cat.eatFood("fish"));
/// ```
///
/// Mocktail will fail the current test case if `cat.eatFood` hasn't been called
/// with `"fish"`. Optionally, call `called` on the result, to verify that the
/// method was called a certain number of times. For example:
///
/// ```dart
/// verify(cat.eatFood("fish")).called(2);
/// verify(cat.eatFood("fish")).called(greaterThan(3));
/// verify(() => cat.eatFood("fish")).called(2);
/// verify(() => cat.eatFood("fish")).called(greaterThan(3));
/// ```
///
/// Note: When mocktail verifies a method call, said call is then excluded from
Expand All @@ -325,7 +324,7 @@ _Verify get verify => _makeVerify(false);
///
/// ```dart
/// cat.eatFood("chicken");
/// verifyNever(cat.eatFood("fish"));
/// verifyNever(() => cat.eatFood("fish"));
/// ```
///
/// Mocktail will pass the current test case, as `cat.eatFood` has not been
Expand All @@ -336,7 +335,7 @@ _Verify get verifyNever => _makeVerify(true);
/// given arguments. For example:
///
/// ```dart
/// verifyInOrder([cat.eatFood("Milk"), cat.sound(), cat.eatFood(any)]);
/// verifyInOrder(() => [cat.eatFood("Milk"), cat.sound(), cat.eatFood(any)]);
/// ```
///
/// This verifies that `eatFood` was called with `"Milk"`, `sound` was called
Expand All @@ -348,8 +347,9 @@ _Verify get verifyNever => _makeVerify(true);
/// For example, if [verifyInOrder] is given these calls to verify:
///
/// ```dart
/// var verification = verifyInOrder(
/// [cat.eatFood(captureAny), cat.chew(), cat.eatFood(captureAny)]);
/// final verification = verifyInOrder(
/// () => [cat.eatFood(captureAny), cat.chew(), cat.eatFood(captureAny)],
/// );
/// ```
///
/// then `verification` is a list which contains a `captured` getter which
Expand All @@ -366,13 +366,18 @@ _Verify get verifyNever => _makeVerify(true);
/// other calls were made to `eatFood` or `sound` between the three given
/// calls, or before or after them, the verification will still succeed.
List<VerificationResult> Function<T>(
List<T> recordedInvocations,
List<T> Function() recordedInvocations,
) get verifyInOrder {
if (_verifyCalls.isNotEmpty) {
throw StateError(_verifyCalls.join());
}
_verificationInProgress = true;
return <T>(List<T> _) {
return <T>(List<T> Function() _) {
try {
_();
} catch (_) {
if (_ is! TypeError) rethrow;
}
_verificationInProgress = false;
var verificationResults = <VerificationResult>[];
var time = DateTime.fromMillisecondsSinceEpoch(0);
Expand Down
2 changes: 1 addition & 1 deletion packages/mocktail/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: mocktail
description: A Dart mocking library which simplifies mocking with null safety support and no manual mocks or code generation.
version: 0.0.2-dev.2
version: 0.0.2-dev.3
repository: https://github.com/felangel/mocktail
homepage: https://github.com/felangel/mocktail/tree/main/packages/mocktail

Expand Down
54 changes: 54 additions & 0 deletions packages/mocktail/test/mockito_compat/nnbd_support_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';

class Foo {
String? returnsNullableString() => 'Hello';

String returnsNonNullableString() => 'Hello';
}

class MockFoo extends Mock implements Foo {}

void main() {
late MockFoo mock;

setUp(() {
mock = MockFoo();
});

tearDown(resetMocktailState);

group('Using nSM out of the box,', () {
test('nSM returns the dummy value during method stubbing', () {
// Trigger method stubbing.
final whenCall = when;
final stubbedResponse = mock.returnsNullableString();
expect(stubbedResponse, equals(null));
whenCall(() => stubbedResponse).thenReturn('A');
});

test('nSM returns the dummy value during method call verification', () {
when(() => mock.returnsNullableString()).thenReturn('A');

// Make a real call.
final realResponse = mock.returnsNullableString();
expect(realResponse, equals('A'));

// Trigger method call verification.
final verifyCall = verify;
final verificationResponse = mock.returnsNullableString();
expect(verificationResponse, equals(null));
verifyCall(() => verificationResponse);
});

test(
'nSM returns the dummy value during method call verification, using '
'verifyNever', () {
// Trigger method call verification.
final verifyNeverCall = verifyNever;
final verificationResponse = mock.returnsNullableString();
expect(verificationResponse, equals(null));
verifyNeverCall(() => verificationResponse);
});
});
}
38 changes: 24 additions & 14 deletions packages/mocktail/test/mockito_compat/verify_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class _RealClass {
String? methodWithNamedArgs(int x, {int? y}) => 'Real';
String? methodWithOnlyNamedArgs({int? y = 0, int? z}) => 'Real';
String? get getter => 'Real';
String get nsGetter => 'Real';
set setter(String arg) {
throw StateError('I must be mocked');
}
Expand Down Expand Up @@ -436,7 +437,15 @@ void main() {
mock
..methodWithoutArgs()
..getter;
verifyInOrder([mock.methodWithoutArgs(), mock.getter]);
verifyInOrder(() => [mock.methodWithoutArgs(), mock.getter]);
});

test('right order passes (ns)', () {
when(() => mock.nsGetter).thenReturn('mock');
mock
..methodWithoutArgs()
..nsGetter;
verifyInOrder(() => [mock.methodWithoutArgs(), mock.nsGetter]);
});

test('wrong order fails', () {
Expand All @@ -446,7 +455,7 @@ void main() {
expectFail(
'Matching call #1 not found. All calls: '
'_MockedClass.methodWithoutArgs(), _MockedClass.getter', () {
verifyInOrder([mock.getter, mock.methodWithoutArgs()]);
verifyInOrder(() => [mock.getter, mock.methodWithoutArgs()]);
});
});

Expand All @@ -457,10 +466,10 @@ void main() {
expectFail(
'There is already a verification in progress, '
'check if it was not called with a verify argument(s)', () {
verifyInOrder([
verify(() => mock.getter),
verify(() => mock.methodWithoutArgs()),
]);
verifyInOrder(() => [
verify(() => mock.getter),
verify(() => mock.methodWithoutArgs()),
]);
});
});

Expand All @@ -469,7 +478,7 @@ void main() {
expectFail(
'Matching call #1 not found. All calls: '
'_MockedClass.methodWithoutArgs()', () {
verifyInOrder([mock.methodWithoutArgs(), mock.getter]);
verifyInOrder(() => [mock.methodWithoutArgs(), mock.getter]);
});
});

Expand All @@ -478,7 +487,7 @@ void main() {
..methodWithoutArgs()
..getter
..methodWithoutArgs();
verifyInOrder(
verifyInOrder(() =>
[mock.methodWithoutArgs(), mock.getter, mock.methodWithoutArgs()]);
});

Expand All @@ -487,11 +496,11 @@ void main() {
..methodWithNormalArgs(1)
..methodWithoutArgs()
..methodWithNormalArgs(2);
final captured = verifyInOrder([
mock.methodWithNormalArgs(captureAny()),
mock.methodWithoutArgs(),
mock.methodWithNormalArgs(captureAny())
]).captured;
final captured = verifyInOrder(() => [
mock.methodWithNormalArgs(captureAny()),
mock.methodWithoutArgs(),
mock.methodWithNormalArgs(captureAny())
]).captured;
expect(captured, hasLength(3));
expect(captured[0], equals([1]));
expect(captured[1], equals(<int>[]));
Expand All @@ -508,7 +517,8 @@ void main() {
'_MockedClass.methodWithoutArgs(), _MockedClass.methodWithoutArgs(), '
'_MockedClass.getter', () {
verifyInOrder(
[mock.methodWithoutArgs(), mock.getter, mock.methodWithoutArgs()],
() =>
[mock.methodWithoutArgs(), mock.getter, mock.methodWithoutArgs()],
);
});
});
Expand Down

0 comments on commit 99ea9f8

Please sign in to comment.