Basic usage of dmocks

/++
   An example of using mock objects to test a class.
 ++/

import dmocks.Mocks;

/**
   I use an interface here because it's easy to use.
   I could have used a class instead.
 **/
interface IAssociate (T) {
   uint calculate (ubyte[] data);
   bool isStored (T item);
   void store (T item);
}

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 {
         return 0;
      }
   }

   // At this point, I don't actually have IAssociate implemented anywhere.
   unittest {
      // First we create a Mocker; through it we'll create mock objects and manage them.
      auto mock = new Mocker;
      // This gives us a mock of an IAssociate!(real). It's an actual object that implements
      // that interface; you can use it just like the real thing.
      auto associate = mock.mock!(IAssociate!(real));
      real number = 7.23;
      ubyte[] data = new ubyte[4];
      uint result = 42;

      // Right now, we're in record state. This is something that we expect to happen later
      // later in the test: someone will call isStored, with that particular argument, and
      // the method will return false when that happens.
      mock.expect(associate.isStored(number)).returns(false);

      // This is another way of setting up a call -- and unfortunately it's the only way
      // of setting up a call for a void method.
      associate.store(number);

      // One more expectation. The arguments have to match; at least, opEquals has to return
      // true for them; so keep that in mind.
      mock.expect(associate.calculate(data)).returns(result);

      // Now we want to switch from recording things to actually doing stuff and making sure
      // the object we're testing does what we expect.
      mock.replay();

      // From here on out, the mocker is making sure that we don't do anything more than we
      // set up earlier. If we do something unexpected, like calling a method with the wrong
      // arguments, we'll get hit with an ExpectationViolationException. So let's get on with it.
      auto target = new ToTest(associate);
      assert (target.calculate(number, data) == result);
      
      // Now we just call this to make sure everything happened correctly. If something
      // failed to happen that should have happened, this will throw an 
      // ExpectationViolationException.
      mock.verify();
   }
}

back to Examples