blob: 0732cb406bf29784cbcd8dbadf41b3be1c8d7098 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* A simple mocking/spy library.
*
* To create a mock objects for some class T, create a new class using:
*
* class MockT extends Mock implements T {};
*
* Then specify the [Behavior] of the Mock for different methods using
* [when] (to select the method and parameters) and then the [Action]s
* for the [Behavior] by calling [thenReturn], [alwaysReturn], [thenThrow],
* [alwaysThrow], [thenCall] or [alwaysCall].
*
* [thenReturn], [thenThrow] and [thenCall] are one-shot so you would
* typically call these more than once to specify a sequence of actions;
* this can be done with chained calls, e.g.:
*
* m.when(callsTo('foo')).
* thenReturn(0).thenReturn(1).thenReturn(2);
*
* [thenCall] and [alwaysCall] allow you to proxy mocked methods, chaining
* to some other implementation. This provides a way to implement 'spies'.
*
* For getters and setters, use "get foo" and "set foo"-style arguments
* to [callsTo].
*
* You can disable logging for a particular [Behavior] easily:
*
* m.when(callsTo('bar')).logging = false;
*
* You can then use the mock object. Once you are done, to verify the
* behavior, use [getLogs] to extract a relevant subset of method call
* logs and apply [Matchers] to these through calling [verify].
*
* A Mock can be given a name when constructed. In this case instead of
* keeping its own log, it uses a shared log. This can be useful to get an
* audit trail of interleaved behavior. It is the responsibility of the user
* to ensure that mock names, if used, are unique.
*
* Limitations:
*
* * only positional parameters are supported (up to 10);
* * to mock getters you will need to include parentheses in the call
* (e.g. m.length() will work but not m.length).
*
* Here is a simple example:
*
* class MockList extends Mock implements List {};
*
* List m = new MockList();
* m.when(callsTo('add', anything)).alwaysReturn(0);
*
* m.add('foo');
* m.add('bar');
*
* getLogs(m, callsTo('add', anything)).verify(happenedExactly(2));
* getLogs(m, callsTo('add', 'foo')).verify(happenedOnce);
* getLogs(m, callsTo('add', 'isNull)).verify(neverHappened);
*
* Note that we don't need to provide argument matchers for all arguments,
* but we do need to provide arguments for all matchers. So this is allowed:
*
* m.when(callsTo('add')).alwaysReturn(0);
* m.add(1, 2);
*
* But this is not allowed and will throw an exception:
*
* m.when(callsTo('add', anything, anything)).alwaysReturn(0);
* m.add(1);
*
* Here is a way to implement a 'spy', which is where we log the call
* but then hand it off to some other function, which is the same
* method in a real instance of the class being mocked:
*
* class Foo {
* bar(a, b, c) => a + b + c;
* }
*
* class MockFoo extends Mock implements Foo {
* Foo real;
* MockFoo() {
* real = new Foo();
* this.when(callsTo('bar')).alwaysCall(real.bar);
* }
* }
*
* However, there is an even easier way, by calling [Mock.spy], e.g.:
*
* var foo = new Foo();
* var spy = new Mock.spy(foo);
* print(spy.bar(1, 2, 3));
*
* Spys created with Mock.spy do not have user-defined behavior;
* they are simply proxies, and thus will throw an exception if
* you call [when]. They capture all calls in the log, so you can
* do assertions on their history, such as:
*
* spy.getLogs(callsTo('bar')).verify(happenedOnce);
*
* [pub]: http://pub.dartlang.org
*/
library mock;
export 'src/action.dart';
export 'src/behavior.dart';
export 'src/call_matcher.dart';
export 'src/log_entry.dart';
export 'src/log_entry_list.dart';
export 'src/mock.dart';
export 'src/responder.dart';
export 'src/result_matcher.dart';
export 'src/result_set_matcher.dart';
export 'src/times_matcher.dart';