Search code examples
mspecmachine.fakes

How do I use Machine.Fakes to ensure a constructor does not call a local method?


Given an constructor that is expected to throw an exception:

public class MyObject
{
  public MyObject(String name)
  {
    if (String.IsNullOrEmpty(name))
      throw new ArgumentNullException("name");

    this.Initialize();
  }

  protected virtual void Initialize()
  {
    // do stuff
  }
}

How would I use Machine.Fakes with Rhino (the default, and I am moving to Rhino) to mock up this class, and test that:

  1. It throws the expected exception
  2. It does not call Initialize()

With Moq, I can mock the actual MyObject class itself and set the property on the mock Callbase = true to get it to act like a normal class.

I can then verify both that an exception was thrown, and that the method was not called with this:

// all pseudo code to prove my point of "creating an instance"
//
void when_creating_new_MyObject_with_null_Name_should_throw_Exception()
{
  // arrange
  Mock<MyObject> myObjectToTest = new Mock<MyObject>(String.Empty);
  myObjectToTest.Callbase = true;

  // act
  Assert.Throws<ArgumentNullException>(() => 
    var instance = myObjectToTest.Object;
  );
}

void when_creating_new_MyObject_with_null_Name_should_not_call_Initialize()
{
  // arrange
  Mock<MyObject> myObjectToTest = new Mock<MyObject>(String.Empty);
  myObjectToTest.Callbase = true;

  // act
  try
  {
    // creates an instance
    var instance = myObjectToTest.Object;
  }
  catch {}

  // assert
  myObjectToTest.Verify(x => x.Initialize(), Times.Never());
}

But I am having trouble figuring out how to use MSpec w/Fakes to mock this up:

[Subject(typeof(MyObject), "when instantiating a new instance")
class with_null_Name
{
  static MyObject myObjectToTest;
  static Exception expectedException;

  Establish context =()=>
    myObjectToTest = An<MyObject>(String.Empty);

  Because of;  // I don't think there is anything to act on here?

  It should_throw_Exception;
    // how to capture exception with An<T>()?

  It should_not_call_Initialize = () =>
    myObjectToTest.WasNotToldTo(x => x.Initialize());

}

I do know about and use the Catch.Exception(...) normally in my Because of acts. But this use case doesn't seem to work with that.

Any pointers would be appreciated.

Thanks!

Disclaimer: The real-world use case is quite complex with heavy objects to inititalize that is quite expensive with cached backing members. The above code is just a simplified version.


Solution

  • Personally, I'm not accustomed to using mocking frameworks to mock things within the unit under test. I use mocks to break external dependencies using dependency injection. I'm by no means an expert at this, but my gut feeling is that this is too fine-grained a detail to test.

    You say that your real world situation has lots of objects to initialize; couldn't you mock one or more of those objects and check that they aren't called? Or, use dependency injection to inject some fake object in which you can set a flag.

    These suggestions all seem rather smelly to me. In the end, you know if you threw an exception that Initialize wasn't called. I think I understand that you're trying to ensure a bug doesn't creep in at a future edit, but are you in fact unit-testing the developer here? I personally would have thought it was sufficient to verify that an exception is thrown when bad data is supplied. I'm interested to hear any differing opinions though.