Remove typed_mock

Bug: https://github.com/dart-lang/sdk/issues/32271
Change-Id: I32d7708f269b9618f6a031f0323f5cea646066f3
Reviewed-on: https://dart-review.googlesource.com/42862
Reviewed-by: Kevin Moore <kevmoo@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-02-21 22:22:32 +00:00 committed by commit-bot@chromium.org
parent ebd16bd33f
commit fae3a83629
8 changed files with 0 additions and 1069 deletions

View file

@ -101,7 +101,6 @@ test_reflective_loader:third_party/pkg/test_reflective_loader/lib
testing:pkg/testing/lib
tuple:third_party/pkg/tuple/lib
typed_data:third_party/pkg/typed_data/lib
typed_mock:pkg/typed_mock/lib
unittest:third_party/pkg/unittest/lib
usage:third_party/pkg/usage/lib
utf:third_party/pkg/utf/lib

View file

@ -81,7 +81,6 @@ Future main(List<String> arguments) async {
await compileModule('meta');
if (isTravis) {
await compileModule('microlytics', libs: ['html_channels']);
await compileModule('typed_mock');
}
// Under third_party/pkg.

View file

@ -52,7 +52,6 @@ vm/testcases/*: SkipByDesign # These are not tests but input for tests.
[ $compiler == dart2analyzer ]
dev_compiler/test/options/*: SkipByDesign
typed_mock/test/typed_mock_test: StaticWarning
[ $compiler != dart2analyzer ]
analyzer/test/src/summary/summarize_fasta_test: RuntimeError, Slow

View file

@ -1,26 +0,0 @@
Copyright 2014, the Dart project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,214 +0,0 @@
A library for mocking classes and verifying expected interaction with mocks.
It is inspired by [Mockito](https://code.google.com/p/mockito/).
Features of this package:
- Code-completion, static validation, search and refactoring all work properly with mocks.
- Much better error messages for unit testing.
- Works with concrete and abstract classes.
- Does not use mirrors.
- No dependent packages.
Other Mock libraries for Dart:
- https://pub.dartlang.org/packages/mockito
- https://pub.dartlang.org/packages/mock (deprecated)
## Tutorial
Let's take the simple case of making sure that a method is called. The first step is to create a mock of the object, as shown below. One nice feature of Dart is that all classes automatically define interfaces, so you don't need to separately define the interface.
```dart
import 'package:typed_mock/typed_mock.dart';
class Dog {
String speak() => "Woof!";
}
class MockDog extends TypedMock implements Dog {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
```
All of the magic happens because of the noSuchMethod() function. None of the functions for Animal are actually defined because we used `implements` instead of `extends`. Therefore, all calls to this object will end up in `noSuchMethod()`.
#### Verify a function is called
Here's the code to verify that the function is called:
```dart
void main() {
final dog = new MockDog();
verifyZeroInteractions(dog);
dog.speak();
verify(dog.speak()).once();
verifyNoMoreInteractions(dog);
}
```
One of the interesting features of typed_mock is that it internally tracks all calls to each mock object, then tracks which calls have been matched with a verify() call and which not. Therefore, typed_mock is able to detect unexpected calls, even if those calls are made to methods that didn't exist when the test was written. This can be a good incentive to update your tests whenever you change a class.
After creating the `MockAnimal` object, we call `verifyZeroInteractions()` to make sure that the object starts in a clean state. Next we call the `speak()` method, then prove that the speak function was actually called with `verify().once()`.
There are several other functions for verifying calls that can be used instead of `once()`:
- `atLeastOnce()` Ensure the function was called one or more times.
- `times(n)` Ensure the function was called exactly `n` times.
- `atLeast(n)` Ensure the function was called `n` or more times.
- `atMost(n)` Ensure the function was called no more than `n` times.
- `any()` Mark the function call as verified if it was called, but don't fail if it wasn't called.
- `never()` Ensure the function was never called. It's often better to use `verifyNoMoreInteractions()` instead.
#### Configure the mock to return a value
Here's how to return a value from `speak()`:
```dart
void main() {
final dog = new MockDog();
when(dog.speak()).thenReturn("woof");
final s = dog.speak();
print("$s");
verify(dog.speak()).once();
verifyNoMoreInteractions(dog);
}
```
What if `speak()` took the name of an animal as a parameter? When typed_mock tracks a function call, the call tracking is based on the function name and the parameters. For example:
```dart
import 'package:typed_mock/typed_mock.dart';
abstract class Animal {
String speak();
}
class MockAnimal extends TypedMock implements Animal {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
void main() {
final animal = new MockAnimal();
when(animal.speak("dog")).thenReturn("woof");
final s = animal.speak();
print("$s");
verify(animal.speak("dog")).once();
}
```
Note that you can reset the call and verify tracking using `resetInteractions()`. However, there is no way to reset the `when()` calls. Create a new mock instead.
You can define different results based on the value of the parameter. Notice that the calls to `verify()` explicitly states the parameter value:
```dart
void main() {
final animal = new MockAnimal();
when(animal.speak("cat")).thenReturn("meow");
when(animal.speak("dog")).thenReturn("woof");
final s = animal.speak("cat"); // Prints: meow
verify(animal.speak("cat")).once();
verify(animal.speak("dog")).never();
}
```
#### Match any value for a parameter
Sometimes you don't care about the exact value of the parameter. That's when `anyString` is used, along with its siblings `anyInt`, `anyBool` and `anyObject`.
The value `anyString` is a matcher that matches any String value. For example, here's how to use `anyString` in a call to `when()`:
```dart
void main() {
final animal = new MockAnimal();
when(animal.speak(anyString)).thenReturn("meow");
final s1 = animal.speak("cat");
final s2 = animal.speak("dog");
print("$s1 $s2"); // Prints: meow meow
verify(animal.speak(anyString)).times(2);
}
```
You can also use `anyString` in `verify()` calls, even if the `when()` calls use exact values. For example:
```dart
void main() {
final animal = new MockAnimal();
when(animal.speak("cat")).thenReturn("meow");
when(animal.speak("dog")).thenReturn("woof");
var s
s = animal.speak("cat");
s = animal.speak("cat");
s = animal.speak("dog");
verify(animal.speak(anyString)).times(3);
}
```
You can use `anyString` as the parameter for calculated values:
```dart
when(animal.speak(anyString)).thenInvoke((String s) => 'The $s speaks!');
```
In addition to `thenReturn()` and `thenInvoke()`, typed_mock supports `thenReturnList()` and `thenThrow()`. See the link at the end of this document for examples.
#### Mocking operator[] and operator[]=
The typed_mock package is able to track set and get access with operators `[]=` and `[]`, respectively. There's nothing special about these operators - they are just functions with non-alphanumeric names that takes two or one parameters. As with other functions, typed_mock tracks both the index and the value as needed. Note the syntax to verify that a particular array element was assigned a particular value. The act of assigning true is tracked separately from the act of assigning false. The syntax is straightforward.
```dart
import 'package:typed_mock/typed_mock.dart';
abstract class Tracker {
operator [](int index);
operator []=(int index, bool b);
}
class MockTracker extends TypedMock implements Tracker {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
void main() {
final tracker = new MockTracker();
tracker[2] = true;
when(tracker[3]).thenReturn(false);
when(tracker[4]).thenReturn(true);
bool x = tracker[3];
bool y = tracker[4];
print("$x $y");
verify(tracker[1] = true).never();
verify(tracker[2] = false).never();
verify(tracker[2] = true).once();
verify(tracker[3]).once();
verify(tracker[4]).once();
verify(tracker[5]).never();
}
```
#### Passing mocks as closures
Passing a mock as a function parameter may not behave as you expect because a hidden function is called in the mock to get the closure. The solution is to wrap the call in a separate closure. For example, the call to `verifyNoMoreInteractions()` fails because the reference to `dog.speak` caused a hidden function to be called in `MockDog`.
```dart
void doSomething(String myfunc()) {}
void main() {
final dog = new MockDog();
doSomething(dog.speak);
verifyNoMoreInteractions(dog);
}
```
The solution is as follows:
```dart
void doSomething(String myfunc()) {}
void main() {
final dog = new MockDog();
doSomething(() => dog.speak());
verifyNoMoreInteractions(dog);
}
```
## More Information
For additional examples, see the [unit tests](https://github.com/dart-lang/sdk/blob/master/pkg/typed_mock/test/typed_mock_test.dart).

View file

@ -1,426 +0,0 @@
library typed_mock;
_InvocationMatcher _lastMatcher;
/// Enables stubbing methods.
///
/// Use it when you want the mock to return a particular value when a particular
/// method, getter or setter is called.
///
/// when(obj.testProperty).thenReturn(10);
/// expect(obj.testProperty, 10); // pass
///
/// You can specify multiple matchers, which are checked one after another.
///
/// when(obj.testMethod(anyInt)).thenReturn('was int');
/// when(obj.testMethod(anyString)).thenReturn('was String');
/// expect(obj.testMethod(42), 'was int'); // pass
/// expect(obj.testMethod('foo'), 'was String'); // pass
///
/// You can even provide a function to calculate results.
/// Function can be also used to capture invocation arguments (if you test some
/// consumer).
///
/// when(obj.testMethod(anyInt)).thenInvoke((int p) => 10 + p);
/// expect(obj.testMethod(1), 11); // pass
/// expect(obj.testMethod(5), 15); // pass
Behavior when(_ignored) {
try {
var mock = _lastMatcher._mock;
mock._removeLastInvocation();
// set behavior
var behavior = new Behavior._(_lastMatcher);
_lastMatcher._behavior = behavior;
return behavior;
} finally {
// clear to prevent memory leak
_lastMatcher = null;
}
}
/// Clears all interactions remembered so far.
resetInteractions(TypedMock mock) {
mock._invocations.clear();
mock._verifiedInvocations.clear();
}
/// Verifies certain behavior happened a specified number of times.
Verifier verify(_ignored) {
try {
var mock = _lastMatcher._mock;
mock._removeLastInvocation();
// set verifier
return new Verifier._(mock, _lastMatcher);
} finally {
// clear to prevent memory leak
_lastMatcher = null;
}
}
/// Verifies that the given mock doesn't have any unverified interaction.
void verifyNoMoreInteractions(TypedMock mock) {
var notVerified = mock._computeNotVerifiedInvocations();
// OK
if (notVerified.isEmpty) {
return;
}
// fail
var invocationsString = _getInvocationsString(notVerified);
throw new VerifyError('Unexpected interactions:\n$invocationsString');
}
/// Verifies that no interactions happened on the given mock.
void verifyZeroInteractions(TypedMock mock) {
var invocations = mock._invocations;
// OK
if (invocations.isEmpty) {
return;
}
// fail
var invocationsString = _getInvocationsString(invocations);
throw new VerifyError('Unexpected interactions:\n$invocationsString');
}
/// [VerifyError] is thrown when one of the [verify] checks fails.
class VerifyError {
final String message;
VerifyError(this.message);
String toString() => 'VerifyError: $message';
}
String _getInvocationsString(Iterable<Invocation> invocations) {
var buffer = new StringBuffer();
invocations.forEach((invocation) {
var member = invocation.memberName;
buffer.write(member);
buffer.write(' ');
buffer.write(invocation.positionalArguments);
buffer.write(' ');
buffer.write(invocation.namedArguments);
buffer.writeln();
});
return buffer.toString();
}
class _InvocationMatcher {
final Symbol _member;
final TypedMock _mock;
final List<ArgumentMatcher> _matchers = [];
Behavior _behavior;
_InvocationMatcher(this._mock, this._member, Invocation invocation) {
invocation.positionalArguments.forEach((argument) {
ArgumentMatcher matcher;
if (argument is ArgumentMatcher) {
matcher = argument;
} else {
matcher = new _ArgumentMatcher_equals(argument);
}
_matchers.add(matcher);
});
}
bool match(Invocation invocation) {
var arguments = invocation.positionalArguments;
if (arguments.length != _matchers.length) {
return false;
}
for (int i = 0; i < _matchers.length; i++) {
var matcher = _matchers[i];
var argument = arguments[i];
if (!matcher.matches(argument)) {
return false;
}
}
return true;
}
}
class Behavior {
final _InvocationMatcher _matcher;
Behavior._(this._matcher);
bool _thenFunctionEnabled = false;
Function _thenFunction;
bool _returnAlwaysEnabled = false;
var _returnAlways;
bool _returnListEnabled = false;
List _returnList;
int _returnListIndex;
bool _throwExceptionEnabled = false;
var _throwException;
/// Invokes the given [function] with actual arguments and returns its result.
Behavior thenInvoke(Function function) {
_reset();
_thenFunctionEnabled = true;
_thenFunction = function;
return this;
}
/// Returns the specific value.
Behavior thenReturn(value) {
_reset();
_returnAlwaysEnabled = true;
_returnAlways = value;
return this;
}
/// Returns values from the [list] starting from first to the last.
/// If the end of list is reached a [StateError] is thrown.
Behavior thenReturnList(List list) {
_reset();
_returnListEnabled = true;
_returnList = list;
_returnListIndex = 0;
return this;
}
/// Throws the specified [exception] object.
Behavior thenThrow(exception) {
_reset();
_throwExceptionEnabled = true;
_throwException = exception;
return this;
}
_reset() {
_thenFunctionEnabled = false;
_returnAlwaysEnabled = false;
_returnListEnabled = false;
_throwExceptionEnabled = false;
}
dynamic _getReturnValue(Invocation invocation) {
// function
if (_thenFunctionEnabled) {
return Function.apply(_thenFunction, invocation.positionalArguments,
invocation.namedArguments);
}
// always
if (_returnAlwaysEnabled) {
return _returnAlways;
}
// list
if (_returnListEnabled) {
if (_returnListIndex >= _returnList.length) {
throw new StateError('All ${_returnList.length} elements for '
'${_matcher._member} from $_returnList have been exhausted.');
}
return _returnList[_returnListIndex++];
}
// exception
if (_throwExceptionEnabled) {
throw _throwException;
}
// no value
return null;
}
}
class Verifier {
final TypedMock _mock;
final _InvocationMatcher _matcher;
Verifier._(this._mock, this._matcher);
/// Marks matching interactions as verified and never fails.
void any() {
// mark as verified, but don't check the actual count
_count();
}
/// Verifies that there was no matching interactions.
void never() {
times(0);
}
/// Verifies that there was exactly one matching interaction.
void once() {
times(1);
}
/// Verifies that there was the specified number of matching interactions.
void times(int expected) {
var times = _count();
if (times != expected) {
var member = _matcher._member;
throw new VerifyError('$expected expected, but $times'
' invocations of $member recorded.');
}
}
/// Verifies that there was at least the specified number of matching
/// interactions.
void atLeast(int expected) {
var times = _count();
if (times < expected) {
var member = _matcher._member;
throw new VerifyError('At least $expected expected, but only $times'
' invocations of $member recorded.');
}
}
/// Verifies that there was at least one matching interaction.
void atLeastOnce() {
var times = _count();
if (times == 0) {
var member = _matcher._member;
throw new VerifyError('At least one expected, but only zero'
' invocations of $member recorded.');
}
}
/// Verifies that there was at most the specified number of matching
/// interactions.
void atMost(int expected) {
var times = _count();
if (times > expected) {
var member = _matcher._member;
throw new VerifyError('At most $expected expected, but $times'
' invocations of $member recorded.');
}
}
int _count() {
var times = 0;
_mock._invocations.forEach((invocation) {
if (invocation.memberName != _matcher._member) {
return;
}
if (!_matcher.match(invocation)) {
return;
}
_mock._verifiedInvocations.add(invocation);
times++;
});
return times;
}
}
/// A class to extend mocks from.
/// It supports specifying behavior using [when] and validation of interactions
/// using [verify].
///
/// abstract class Name {
/// String get firstName;
/// String get lastName;
/// }
/// class NameMock extends TypedMock implements Name {
/// noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
/// }
class TypedMock {
final Map<Symbol, List<_InvocationMatcher>> _matchersMap = {};
final List<Invocation> _invocations = [];
final Set<Invocation> _verifiedInvocations = new Set<Invocation>();
noSuchMethod(Invocation invocation) {
_invocations.add(invocation);
var member = invocation.memberName;
// prepare invocation matchers
var matchers = _matchersMap[member];
if (matchers == null) {
matchers = [];
_matchersMap[member] = matchers;
}
// check if there is a matcher
for (var matcher in matchers) {
if (matcher.match(invocation)) {
_lastMatcher = matcher;
// generate value if there is a behavior
if (matcher._behavior != null) {
return matcher._behavior._getReturnValue(invocation);
}
// probably verification
return null;
}
}
// add a new matcher
var matcher = new _InvocationMatcher(this, member, invocation);
matchers.add(matcher);
_lastMatcher = matcher;
}
Iterable<Invocation> _computeNotVerifiedInvocations() {
notVerified(e) => !_verifiedInvocations.contains(e);
return _invocations.where(notVerified);
}
void _removeLastInvocation() {
_invocations.removeLast();
}
}
/// [ArgumentMatcher] checks whether the given argument satisfies some
/// condition.
abstract class ArgumentMatcher {
const ArgumentMatcher();
/// Checks whether this matcher accepts the given argument.
bool matches(val);
}
class _ArgumentMatcher_equals extends ArgumentMatcher {
final expected;
const _ArgumentMatcher_equals(this.expected);
@override
bool matches(val) {
return val == expected;
}
}
class _ArgumentMatcher_anyBool extends ArgumentMatcher {
const _ArgumentMatcher_anyBool();
@override
bool matches(val) {
return val is bool;
}
}
/// Matches any [bool] value.
final anyBool = const _ArgumentMatcher_anyBool() as dynamic;
class _ArgumentMatcher_anyInt extends ArgumentMatcher {
const _ArgumentMatcher_anyInt();
@override
bool matches(val) {
return val is int;
}
}
/// Matches any [int] value.
final anyInt = const _ArgumentMatcher_anyInt() as dynamic;
class _ArgumentMatcher_anyObject extends ArgumentMatcher {
const _ArgumentMatcher_anyObject();
@override
bool matches(val) {
return true;
}
}
/// Matches any [Object] (or subclass) value.
final anyObject = const _ArgumentMatcher_anyObject() as dynamic;
class _ArgumentMatcher_anyString extends ArgumentMatcher {
const _ArgumentMatcher_anyString();
@override
bool matches(val) {
return val is String;
}
}
/// Matches any [String] value.
final anyString = const _ArgumentMatcher_anyString() as dynamic;

View file

@ -1,9 +0,0 @@
name: typed_mock
version: 0.0.4
author: Dart Team <misc@dartlang.org>
description: A library for mocking classes using Mockito-like syntax
homepage: http://www.dartlang.org
environment:
sdk: '>=1.0.0 <2.0.0'
dev_dependencies:
unittest: '>=0.10.0 <0.12.0'

View file

@ -1,391 +0,0 @@
library test.typed_mock;
import 'package:unittest/unittest.dart';
import 'package:typed_mock/typed_mock.dart';
abstract class TestInterface {
int get testProperty;
set testProperty(x);
int get testPropertyB;
String testMethod0();
String testMethod1(a);
String testMethod2(String a, int b);
void testMethodVoid(a);
int operator [](index);
}
class TestInterfaceMock extends TypedMock implements TestInterface {
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
main() {
// lets make it redable
groupSep = ' | ';
group('VerifyError', () {
test('VerifyError', () {
var error = new VerifyError('msg');
expect(error.message, 'msg');
expect(error.toString(), 'VerifyError: msg');
});
});
group('Matchers', () {
test('anyBool', () {
expect(anyBool.matches(true), true);
expect(anyBool.matches(false), true);
expect(anyBool.matches(0), false);
expect(anyBool.matches('0'), false);
});
test('anyInt', () {
expect(anyInt.matches(true), false);
expect(anyInt.matches(-99), true);
expect(anyInt.matches(0), true);
expect(anyInt.matches(42), true);
expect(anyInt.matches('0'), false);
});
test('anyObject', () {
expect(anyObject.matches(true), true);
expect(anyObject.matches(0), true);
expect(anyObject.matches('0'), true);
});
test('anyString', () {
expect(anyString.matches(true), false);
expect(anyString.matches(0), false);
expect(anyString.matches(''), true);
expect(anyString.matches('0'), true);
expect(anyString.matches('abc'), true);
});
});
group('when', () {
TestInterface obj;
setUp(() {
obj = new TestInterfaceMock();
});
test('thenInvoke for getter', () {
when(obj.testProperty).thenInvoke(() => 123);
expect(obj.testProperty, 123);
});
test('thenInvoke for method with 1 argument', () {
when(obj.testMethod1(anyInt)).thenInvoke((int p) => p + 10);
expect(obj.testMethod1(1), 1 + 10);
expect(obj.testMethod1(2), 2 + 10);
expect(obj.testMethod1(10), 10 + 10);
});
test('thenReturn can replace behavior, getter', () {
// set a behavior
when(obj.testProperty).thenReturn(10);
expect(obj.testProperty, 10);
// set another behavior
when(obj.testProperty).thenReturn(20);
expect(obj.testProperty, 20);
});
test('thenReturn for getter', () {
when(obj.testProperty).thenReturn(42);
expect(obj.testProperty, 42);
expect(obj.testProperty, 42);
});
test('thenReturn for []', () {
when(obj[1]).thenReturn(10);
when(obj[2]).thenReturn(20);
when(obj[anyInt]).thenReturn(99);
expect(obj[1], 10);
expect(obj[2], 20);
expect(obj[5], 99);
});
test('thenReturn for method with 0 arguments', () {
when(obj.testMethod0()).thenReturn('abc');
expect(obj.testMethod0(), 'abc');
expect(obj.testMethod0(), 'abc');
});
test('thenReturn for method with 1 argument, anyBool', () {
when(obj.testMethod1(anyBool)).thenReturn('qwerty');
expect(obj.testMethod1(true), 'qwerty');
expect(obj.testMethod1(false), 'qwerty');
});
test('thenReturn for method with 1 argument, anyInt', () {
when(obj.testMethod1(anyInt)).thenReturn('qwerty');
expect(obj.testMethod1(2), 'qwerty');
expect(obj.testMethod1(3), 'qwerty');
});
test('thenReturn for method with 1 argument, anyObject', () {
when(obj.testMethod1(anyObject)).thenReturn('qwerty');
expect(obj.testMethod1([]), 'qwerty');
expect(obj.testMethod1([1, 2, 3]), 'qwerty');
});
test('thenReturn for method with 1 argument, argument value', () {
when(obj.testMethod1(10)).thenReturn('ten');
when(obj.testMethod1(20)).thenReturn('twenty');
expect(obj.testMethod1(10), 'ten');
expect(obj.testMethod1(10), 'ten');
expect(obj.testMethod1(20), 'twenty');
expect(obj.testMethod1(20), 'twenty');
});
test('thenReturn for method with 2 arguments', () {
when(obj.testMethod2(anyString, 10)).thenReturn('any+10');
when(obj.testMethod2(anyString, 20)).thenReturn('any+20');
when(obj.testMethod2(anyString, anyInt)).thenReturn('everything else');
expect(obj.testMethod2('aaa', 10), 'any+10');
expect(obj.testMethod2('bbb', 10), 'any+10');
expect(obj.testMethod2('ccc', 20), 'any+20');
expect(obj.testMethod2('ddd', 20), 'any+20');
expect(obj.testMethod2('eee', 99), 'everything else');
});
test('thenReturnList for getter', () {
when(obj.testProperty).thenReturnList(['a', 'b', 'c']);
expect(obj.testProperty, 'a');
expect(obj.testProperty, 'b');
expect(obj.testProperty, 'c');
expect(() => obj.testProperty, throwsA(new isInstanceOf<StateError>()));
});
test('thenThrow for getter', () {
Exception e = new Exception();
when(obj.testProperty).thenThrow(e);
expect(() => obj.testProperty, throwsA(e));
});
test('thenThrow for setter, anyInt', () {
Exception e = new Exception();
when(obj.testProperty = anyInt).thenThrow(e);
expect(() => (obj.testProperty = 2), throwsA(e));
});
test('thenThrow for setter, argument value', () {
Exception e1 = new Exception('one');
Exception e2 = new Exception('two');
when(obj.testProperty = 1).thenThrow(e1);
when(obj.testProperty = 2).thenThrow(e2);
expect(() => (obj.testProperty = 1), throwsA(e1));
expect(() => (obj.testProperty = 1), throwsA(e1));
expect(() => (obj.testProperty = 2), throwsA(e2));
expect(() => (obj.testProperty = 2), throwsA(e2));
});
});
test('resetInteractions', () {
TestInterfaceMock obj = new TestInterfaceMock();
obj.testProperty;
obj.testMethod0();
resetInteractions(obj);
verifyZeroInteractions(obj);
});
group('verify', () {
TestInterfaceMock obj;
setUp(() {
obj = new TestInterfaceMock();
});
group('times', () {
test('OK, getter', () {
obj.testProperty;
obj.testProperty;
verify(obj.testProperty).times(2);
});
test('OK, 2 getters', () {
obj.testProperty;
obj.testPropertyB;
obj.testProperty;
verify(obj.testProperty).times(2);
verify(obj.testPropertyB).times(1);
});
test('OK, method with 1 argument', () {
obj.testMethod1(10);
obj.testMethod1('abc');
obj.testMethod1(20);
verify(obj.testMethod1(10)).times(1);
verify(obj.testMethod1(20)).times(1);
verify(obj.testMethod1(30)).times(0);
verify(obj.testMethod1(anyInt)).times(2);
verify(obj.testMethod1(anyString)).times(1);
verify(obj.testMethod1(anyBool)).times(0);
});
test('OK, getter, with thenReturn', () {
when(obj.testProperty).thenReturn('abc');
obj.testProperty;
obj.testProperty;
verify(obj.testProperty).times(2);
});
test('OK, void method', () {
obj.testMethodVoid(10);
obj.testMethodVoid(20);
verify(obj.testMethodVoid(anyInt)).times(2);
});
test('mismatch, getter', () {
obj.testProperty;
obj.testProperty;
obj.testProperty;
expect(() {
verify(obj.testProperty).times(2);
}, throwsA(_isVerifyError));
});
});
group('never', () {
test('OK', () {
verify(obj.testProperty).never();
});
test('mismatch', () {
obj.testProperty;
expect(() {
verify(obj.testProperty).never();
}, throwsA(_isVerifyError));
});
});
group('any', () {
test('OK, 0', () {
verify(obj.testProperty).any();
});
test('OK, 1', () {
obj.testProperty;
verify(obj.testProperty).any();
});
});
group('once', () {
test('OK', () {
obj.testProperty;
verify(obj.testProperty).once();
});
test('mismatch, actually 0', () {
expect(() {
verify(obj.testProperty).once();
}, throwsA(_isVerifyError));
});
test('mismatch, actually 2', () {
obj.testProperty;
obj.testProperty;
expect(() {
verify(obj.testProperty).once();
}, throwsA(_isVerifyError));
});
});
group('atLeast', () {
test('OK, 1', () {
obj.testProperty;
verify(obj.testProperty).atLeast(1);
});
test('OK, 2', () {
obj.testProperty;
obj.testProperty;
verify(obj.testProperty).atLeast(1);
verify(obj.testProperty).atLeast(2);
});
test('mismatch', () {
obj.testProperty;
obj.testProperty;
expect(() {
verify(obj.testProperty).atLeast(10);
}, throwsA(_isVerifyError));
});
});
group('atLeastOnce', () {
test('OK, 1', () {
obj.testProperty;
verify(obj.testProperty).atLeastOnce();
});
test('OK, 2', () {
obj.testProperty;
obj.testProperty;
verify(obj.testProperty).atLeastOnce();
});
test('fail', () {
expect(() {
verify(obj.testProperty).atLeastOnce();
}, throwsA(_isVerifyError));
});
});
group('atMost', () {
test('OK, 0', () {
verify(obj.testProperty).atMost(5);
verify(obj.testProperty).atMost(0);
});
test('OK, 2', () {
obj.testProperty;
obj.testProperty;
verify(obj.testProperty).atMost(5);
verify(obj.testProperty).atMost(3);
verify(obj.testProperty).atMost(2);
});
test('mismatch', () {
obj.testProperty;
obj.testProperty;
obj.testProperty;
expect(() {
verify(obj.testProperty).atMost(2);
}, throwsA(_isVerifyError));
});
});
group('verifyNoMoreInteractions', () {
test('OK, 0', () {
verifyNoMoreInteractions(obj);
});
test('OK, single method, 1', () {
obj.testMethod1(10);
verify(obj.testMethod1(anyInt)).any();
verifyNoMoreInteractions(obj);
});
test('fail, 3', () {
obj.testMethod1(10);
obj.testMethod2('foo', 20);
obj.testMethod1(30);
expect(() {
verifyNoMoreInteractions(obj);
}, throwsA(_isVerifyError));
});
});
group('verifyZeroInteractions', () {
test('OK, 0', () {
verifyZeroInteractions(obj);
});
test('OK, 0, local var', () {
var obj = new TestInterfaceMock();
verifyZeroInteractions(obj);
});
test('fail, 1, no verify()', () {
obj.testMethod1(10);
expect(() {
verifyZeroInteractions(obj);
}, throwsA(_isVerifyError));
});
test('fail, 1, with verify()', () {
obj.testMethod1(10);
verify(obj.testMethod1(anyInt)).any();
expect(() {
verifyZeroInteractions(obj);
}, throwsA(_isVerifyError));
});
});
});
}
const _isVerifyError = const isInstanceOf<VerifyError>();