dartmocks 0.5.2+1 copy "dartmocks: ^0.5.2+1" to clipboard
dartmocks: ^0.5.2+1 copied to clipboard

Dart 1 only

A mock framework inspired by RSpec-Mocks.

DartMocks #

Build Status

DartMocks is a mock framework for Dart inspired by RSpec. It's built on top of unittest/mock.

An Introduction to DartMocks (screencast) #

Installation #

Add the DartMocks dependency to your project’s pubspec.yaml.

name: my_project
dependencies:
  dartmocks: any

Then, run pub install.

Finally, import the unittest and dartmocks libraries.

import 'package:unittest/unittest.dart';
import 'package:dartmocks/dartmocks.dart';

Code Under Test #

In all the samples below I am going to test the following two classes:

class Player {
  var currentValue = 0;
  var isOn = true;
  changeVolume(delta) => currentValue += delta;
}

class RemoteControl {
  var player;

  RemoteControl(this.player);

  turnUp() => (player.isOn) ? player.changeVolume(10) : 0;
  turnDown() => (player.isOn) ? player.changeVolume(-10) : 0;
}

Stubbing #

Using the stub(Map conf) Function #

You can pass a configuration object, which maps function names to their return values, to the stub function.

test("stubbing a turned off player", (){
  var player = stub({"get isOn" : false});
  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(0));
});

test("stubbing a turned on player", (){
  var player = stub("Player", {"changeVolume" : 100, "get isOn" : true});
  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(100));
});

Note, that you can optionally pass a name to make error messages more descriptive.

Using stub(String methodName) #

In addition to passing a map to the stub function, you can configure each method individually.

test("stubbing a turned off player", (){
  var player = stub("Player")
               ..stub("get isOn").andReturn(false);

  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(0));
});

You can specify the argument of a stubbed method call as follows:

test("specifying arguments", (){
  var player = stub()
              ..stub("get isOn").andReturn(true)
              ..stub("changeVolume").args(10).andReturn(100)
              ..stub("changeVolume").args(-10).andReturn(-100);

  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(100));
  expect(remote.turnDown(), equals(-100));
});

Throwing #

Configuring a stubbed method to throw an exception is done as follows:

test("throwing an exception", (){
  var player = stub("Player")
               ..stub("get isOn").andThrow("BOOM!");

  var remote = new RemoteControl(player);
  expect(remote.turnUp, throws);
});

Custom Behaviours #

Custom behaviour is specified as follows:

test("calling custom functions", (){
  var player = stub("Player")
              ..stub("get isOn").andReturn(true)
              ..stub("changeVolume").andCall((delta) => delta * 100);

  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(1000));
});

Multiple Behaviours #

If you pass more than one argument to andReturn, andCall, or andThrow, DartMocks will build a sequence of behaviours.

test("returning multiple values", (){
  var player = stub("Player")
               ..stub("get isOn").andReturn(true)
               ..stub("changeVolume").andReturn(10,20,30);

  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(10));
  expect(remote.turnUp(), equals(20));
  expect(remote.turnUp(), equals(30));

  //expect(remote.turnUp(), equals(40)); Will throw: No more actions for method changeVolume.
});

Note, that the stub throws an exception because the changeVolume method sort of “ran out” of return values.

Partial Test Doubles #

A partial test double, being an anti pattern, can still be useful in some situations. To create a partial test double just set the real property on a test double.

test("partial stubs", (){
  var realPlayer = new Player()..isOn=false;
  var playerThatIsAlwaysOn = stub("Partial")
                             ..real = realPlayer
                             ..stub("get isOn").andReturn(true);

  expect(playerThatIsAlwaysOn.isOn, equals(true));
  expect(playerThatIsAlwaysOn.changeVolume(100), equals(100));
});

Pure #

If you don't want your test double to respond to framework methods (e.g., stub or shouldReceive), call pure on it. The pure method returns a test double that can only responds to the messages you configured.

test("pure", (){
  var player = stub({"get isOn" : true});
  var pure = player.pure();

  expect(pure.isOn, equals(true));

  //player.stub will work
  expect(() => pure.stub("blah"), throws);
});

Expectations #

Setting Expectations #

test("setting expectations", (){
  var player = mock()
               ..shouldReceive("get isOn").andReturn(false);

  var remote = new RemoteControl(player);
  remote.turnUp();

  player.verify();
});

The verify method will check if all the set expectations have been met.

Using currentTestRun #

Calling verify on every created mock can be tedious. To help you with that, DartMocks stores all expectations. So you can check all of them at once by calling currentTestRun.verify().

tearDown((){
  currentTestRun.verify();
});

test("setting expectations", (){
  var player = mock()
               ..shouldReceive("get isOn").andReturn(false);

  var remote = new RemoteControl(player);
  remote.turnUp();
});

N Times #

DartMocks allows you to specify how many times a particular method should be called.

test("specifying the number of calls", (){
  var player = mock()
               ..shouldReceive("get isOn").andReturn(false).times(2);

  var remote = new RemoteControl(player);

  remote.turnUp();
  remote.turnUp();
});

Extending Test Doubles #

Using TestDouble #

Both the mock and stub functions return an instance of TestDouble. Which means that you can use the TestDouble class directly.

 test("using TestDouble", (){
  var player = new TestDouble()
                 ..name = "Player"
                 ..stub("get isOn").andReturn(false);

  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(0));
});

TestDouble Implementing an Interface #

There are a few good reasons to implement an interface (e.g., tooling). It can be done as follows:

class TestDoublePlayer extends TestDouble implements Player {}

test("test doubles implementing interfaces", (){
  Player player = new TestDoublePlayer()
                 ..stub("get isOn").andReturn(false);

  var remote = new RemoteControl(player);
  expect(remote.turnUp(), equals(0));
});

Contributors #

  • Victor Savkin
  • Sean Kirby
  • Victor Berchet
0
likes
15
pub points
0%
popularity

Publisher

unverified uploader

A mock framework inspired by RSpec-Mocks.

Repository (GitHub)
View/report issues

License

MIT (LICENSE)

Dependencies

matcher, mock

More

Packages that depend on dartmocks