如何使用Machine.Fakes来确保构造函数不调用本地方法?

时间:2013-07-24 15:02:02

标签: mspec machine.fakes

给定一个预期会抛出异常的构造函数:

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

    this.Initialize();
  }

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

我如何使用Machine.Fakes与Rhino(默认情况下,我正在转向Rhino)来模拟这个类,并测试:

  1. 抛出预期的异常
  2. 它不会调用Initialize()
  3. 使用Moq,我可以模拟实际的MyObject类本身,并在模拟Callbase = true上设置属性,使其像普通类一样运行。

    然后,我可以验证是否抛出了异常,并且未使用此方法调用该方法:

    // 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());
    }
    

    但是我无法弄清楚如何使用MSpec w / Fakes来模拟它:

    [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());
    
    }
    

    我确实知道Catch.Exception(...)行为中的Because of通常情况。但是这个用例似乎并不适用。

    任何指针都会受到赞赏。

    谢谢!

    免责声明:真实世界的用例相当复杂,重要的对象要启动,这对于缓存的后备成员而言非常昂贵。上面的代码只是一个简化版本。

2 个答案:

答案 0 :(得分:3)

对我来说没有意义测试一个模拟的sut,模拟行为是由你在测试方法中定义的。你应该测试真实物体 在这种情况下,您应该只验证在提供错误数据时抛出异常 我想你知道该怎么做但无论如何这里是代码:

[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();
}

答案 1 :(得分:2)

就个人而言,我不习惯使用模拟框架来模拟被测单元中的。我使用模拟来使用依赖注入来破坏外部依赖项。我绝不是这方面的专家,但我的直觉是,这个细节太精细了。

你说你的真实世界情况有很多要初始化的对象;难道你不能模拟这些对象中的一个或多个并检查它们是否被调用?或者,使用依赖注入来注入一些可以设置标志的伪对象。

这些建议对我来说都显得很臭。最后,您知道是否抛出了未调用Initialize的异常。我想我明白你正在努力确保一个错误不会在未来的编辑中蔓延,但你实际上是在对这里的开发人员进行单元测试吗?我个人认为在提供错误数据时验证是否会抛出异常就足够了。我很想听到任何不同的意见。