【问题标题】:Mock an instance inside a class in C#在 C# 中模拟类中的实例
【发布时间】:2013-01-10 16:13:17
【问题描述】:

我正在尝试在类中模拟一个实例。这是类(简化):

public void CreatePhotos(string elementType) 
{ 
    var foo = new PicturesCreation(); 

    //some code here...

    if (elementType == "IO") 
    { 
        foo.CreateIcons(client, new PicturesOfFrogsCreation(), periodFrom, periodTo)
    } 
}

所以我试图模拟这个“new PicturesOfFrogsCreation()”来进行单元测试,看看是否使用这个参数调用了 CreateIcons。我试图在我的测试中使用 Rhino Mocks/AssertWasCalled 方法来实现这一点,但它看起来不起作用,因为我只知道如何模拟接口。你知道是否可以模拟这个吗?

更新:PictureCreation 类的代码:

internal sealed class PicturesCreation 
    { 
      public void CreateIcons(IPictures foo, int periodFrom, int periodTo) 

         { 
            foo.CreateIcons(periodFrom, periodTo); 
         } 
    }

以及PicturesOfFrogsCreation的代码:

internal sealed class PicturesOfFrogsCreation : IPictures
{ 

    public void CreateIcons(int periodFrom, int periodTo) 
      { 
         //Code that implements the method
      } 
}

我写了这个测试,但我不确定它是否写得好:

public void Create_commitment_transaction_should_be_called_for_internal_order() 
    { 

       IPicture fooStub = RhinoStubWrapper<IPicture>.CreateStubObject(); 

       rebuildCommitmentsStub.StubMethod(x => x.CreateIcons(Arg<int>.Is.Anything, Arg<int>.Is.Anything));

       PicturesProcess.CreatePhotos("IO"); 

       rebuildCommitmentsStub.AssertWasCalled(x => x.CreateIcons(Arg<int>.Is.Anything,Arg<int>.Is.Anything));

    }

提前致谢!

一个。

【问题讨论】:

  • 提取接口并使用它而不是具体类型有什么问题?
  • 尝试从安排 -> 行动 -> 断言的角度思考。嘲笑是你安排的一部分。通常,您将“模拟”创建您验证的事物的事物。例如,您可以模拟存储库并描述返回“事物”的行为(即模拟您的 PicturesRepository 并告诉它在要求 pictureId == 42 时返回特定图片)。
  • @sll :问题是'//这里的一些代码'有很多情况,这是我不应该接触的代码。如果它很重要,我可以这样做,但这是一个小错误。

标签: c# rhino-mocks


【解决方案1】:

说实话,您的代码似乎不是为此而设计的。因为您是在方法中实例化实例,然后调用该方法,所以很难模拟出来。

如果您将实例传递给此方法,或者传递给要在字段中捕获的类的构造函数,则可以将其替换为模拟 - 大多数模拟框架(包括 Rhino)都可以这样做,前提是该方法你正在检查的是虚拟的。


编辑:我从您的编辑中看到有问题的类是密封的。这使得它们本质上是不可模仿的。模拟类的工作原理是创建一个继承自被模拟类的代理类 - 如果它是密封的,则无法完成。

【讨论】:

  • 是的,我同意你的观点,它看起来很难测试,但我想我不能碰它:(。
  • 不管怎样,当你谈到在方法中传递实例时,你是指PicturesCreation 类吗?感谢您的意见!
  • 无论是什么实例,您都在努力模拟。我想你说这实际上是 PicturesOfFrogsCreation 类。但请注意我的编辑。
【解决方案2】:

您需要注入您希望模拟的依赖项。局部变量是方法私有的,不能被断言。一个例子 -

public class Photo{
  private IPicturesCreation foo;
  public test(IPicturesCreation picturesCreation)
  {
    foo = picturesCreation;
  }

  public void CreatePhotos(string elementType) 
    { 
    //some code here...

    if (elementType == "IO") 
       { 
           foo.CreateIcons(client, new PicturesOfFrogsCreation(), periodFrom, periodTo)
       } 
    }
}

然后像这样测试它

public class PhotoTest{
    public testFunctionCall(){
    var mockPicturesCreation = new Mock<IPicturesCreation>();
    new Photo(mockPicturesCreation.Object).CreatePhotos("blah");
    mockPicturesCreation.Verify(x => x.CreateIcons(.....), Times.Once);
    }
}

【讨论】:

  • 您的解决方案看起来不错!但我不确定我是否可以将它应用到我的身上。我想在我的测试中捕获新的实例字段,而不仅仅是验证是否调用了该方法。我更新了这个问题,所以也许我可以更清楚,你怎么看?谢谢!
  • +1 给 David M,密封类不可模拟。此外,您仍然需要注入 IPictures 作为构造函数的一部分。我看到您在测试中对 CreateIcons 的调用与方法签名不一致。
【解决方案3】:

正如其他人已经提到的,这段代码不太适合模拟。 不过,如果不能修改代码,还是有一些选择的。

我听说TypeMock 可以模拟密封类,但我从未使用过它。顺便说一句,这是商业软件... 还有Microsoft Fakes Framework(与 VS Premium 一起提供)。我玩了一下,似乎你几乎可以测试任何东西。绝对值得一试!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 2019-11-16
    • 2018-07-30
    • 1970-01-01
    • 2020-07-13
    • 2019-07-27
    • 1970-01-01
    相关资源
    最近更新 更多