Add a Fake class with a throwing noSuchMethod (#191)
Closes #169
Adds a slightly better pattern for current abuses of the `Mock` class
when it is used only to avoid implementing an entire interface rather
than for it's actual mocking capabilities.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7548459..9d1e31a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 4.1.0
+
+* Add a `Fake` class for implementing a subset of a class API as overrides
+ without misusing the `Mock` class.
+
## 4.0.0
* Replace the dependency on the
diff --git a/lib/mockito.dart b/lib/mockito.dart
index 046f68c..87da9da 100644
--- a/lib/mockito.dart
+++ b/lib/mockito.dart
@@ -14,6 +14,7 @@
export 'src/mock.dart'
show
+ Fake,
Mock,
named,
diff --git a/lib/src/mock.dart b/lib/src/mock.dart
index 9672cc6..2d43a95 100644
--- a/lib/src/mock.dart
+++ b/lib/src/mock.dart
@@ -74,6 +74,11 @@
/// 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
+/// [Fake] instead.
+///
/// **WARNING**: [Mock] uses [noSuchMethod](goo.gl/r3IQUH), which is a _form_ of
/// runtime reflection, and causes sub-standard code to be generated. As such,
/// [Mock] should strictly _not_ be used in any production code, especially if
@@ -152,6 +157,54 @@
}
}
+/// Extend or mixin this class to mark the implementation as a [Fake].
+///
+/// A fake has a default behavior for every field and method of throwing
+/// [UnimplementedError]. Fields and methods that are excersized by the code
+/// under test should be manually overridden in the implementing class.
+///
+/// A fake does not have any support for verification or defining behavior from
+/// the test, it cannot be used as a [Mock].
+///
+/// In most cases a shared full fake implementation without a `noSuchMethod` is
+/// preferable to `extends Fake`, however `extends Fake` is preferred against
+/// `extends Mock` mixed with manual `@override` implementations.
+///
+/// __Example use__:
+///
+/// // Real class.
+/// class Cat {
+/// String meow(String suffix) => 'Meow$suffix';
+/// String hiss(String suffix) => 'Hiss$suffix';
+/// }
+///
+/// // Fake class.
+/// class FakeCat extends Fake implements Cat {
+/// @override
+/// String meow(String suffix) => 'FakeMeow$suffix';
+/// }
+///
+/// void main() {
+/// // Create a new fake Cat at runtime.
+/// var cat = new FakeCat();
+///
+/// // Try making a Cat sound...
+/// print(cat.meow('foo')); // Prints 'FakeMeowfoo'
+/// print(cat.hiss('foo')); // Throws
+/// }
+///
+/// **WARNING**: [Fake] uses [noSuchMethod](goo.gl/r3IQUH), which is a _form_ of
+/// runtime reflection, and causes sub-standard code to be generated. As such,
+/// [Fake] should strictly _not_ be used in any production code, especially if
+/// used within the context of Dart for Web (dart2js, DDC) and Dart for Mobile
+/// (Flutter).
+abstract class Fake {
+ @override
+ dynamic noSuchMethod(Invocation invocation) {
+ throw UnimplementedError(invocation.memberName.toString().split('"')[1]);
+ }
+}
+
typedef _ReturnsCannedResponse = CallPair<dynamic> Function();
// When using an [ArgMatcher], we transform our invocation to have knowledge of
diff --git a/pubspec.yaml b/pubspec.yaml
index 8903ae8..3570b41 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: mockito
-version: 4.0.0
+version: 4.1.0
authors:
- Dmitriy Fibulwinter <fibulwinter@gmail.com>