/++
   An example of using mock objects to test a class.
   Introducing repeats. We assume that you know everything from the previous example,
   or at least don't mind learning via reading method names.
 ++/

import dmocks.Mocks;

/**
   Again, an interface, so I don't have to put an implementation for any
   of these methods in the example, or worry that any of the methods can't
   be mocked.
 **/
interface IAssociate (T) {
   uint calculate (ubyte[] data);
   bool isStored (T item);
   void store (T item);
   void convenienceMethod ();
}

class ToTest {
   private IAssociate!(real) _associate;
   
   public this (IAssociate!(real) associate) {
      _associate = associate;
   }

   uint calculate (real number, ubyte[] data) {
      if (!_associate.isStored(number)) {
         _associate.store(number);
         return _associate.calculate(data);
      } else {
         uint result = 0;
         for (uint i = _associate.calculate(data); i < number; i++) {
            result += _associate.calculate(data);
            _associate.store(number);
         }
         return result;
      }
   }

   unittest {
      // As always, we start with a Mocker.
      auto mock = new Mocker;
      // And then with our mock object, and some test data.
      auto associate = mock.Mock!(IAssociate!(real));
      real number = 47.23;
      ubyte[] data = new ubyte[4];
      uint result = 42;

      // A typical expectation.
      mock.expect(associate.isStored(number)).returns(true);

      // We'll say that this function can be called lots of extra times without side effects.
      // So it doesn't really matter how many times it's called:
      mock.expect(associate.calculate(data)).returns(result).repeatAny();

      // But this one, we can only call a certain number of times:
      associate.store(number);
      mock.lastCall().repeat(5);

      // There's a convenience method, and let's say we don't mind if it's called at all, but
      // we only want to call it once at most:
      associate.convenienceMethod();
      mock.lastCall.repeat(0, 1);

      // Now we can run the test proper.
      mock.Replay();

      auto target = new ToTest(associate);
      assert (target.calculate(number, data) == result * 5);
      
      mock.verify;
   }
}

back to Examples