/++
   An example of using mock objects to test a class.
   Demonstrates using delegates and exceptions to modify behavior of mocked objects.
 ++/

/**
   Standard interface.
 **/
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(157.2342);
         return _associate.calculate(data);
      } else {
         return 0;
      }
   }

   unittest {
      // The mocker, as always.
      auto mock = new Mocker;
      // And the setup of data.
      auto associate = mock.mock!(IAssociate!(real));
      real number = 7.23;
      ubyte[] data = new ubyte[4];
      uint result = 42;

      // This time, I want to throw an exception and test the error handling.
      mock.expect(associate.isStored(number)).throws(new AbandonedMutexException());

      // Here, let's say we want to verify which numbers are recorded. Let's say we want
      // to make sure that their integral components are prime -- so we'd accept 7.2 or
      // 11.021, but not 9.5.
      bool badResultStored = false;
      associate.store(number);
      mock.lastCall
         .ignoreArgs
         .action((real num) { 
             if (!isPrime(cast(int)num)) {
                // I'm setting a flag and raising an error because the thing we're testing
                // could catch the error.
                badResultStored = true;
                throw new Error("bad result was stored");
             }
         });


      mock.expect(associate.calculate(data)).returns(result);

      // And continue with the rest of the test.
      mock.replay();

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

back to Examples