Question

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.

Was it helpful?

Solution 2

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.

OTHER TIPS

To me do not make sense test a mocked sut, the mock behavior is defined by you in test method. You should test the real object.
In this case you should only verify that an exception is thrown when bad data is supplied.
I think you know how to do but anyway here's the code:

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

    Because of = () => expectedException = Catch.Exception(
                    () => myObjectToTest = new MyObject(String.Empty));

    It should_fail = () => expectedException.ShouldNotBeNull();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top