【问题标题】:Using Moq : Mock object update automatically?使用起订量:模拟对象自动更新?
【发布时间】:2017-07-07 05:56:53
【问题描述】:

我是 MoQ 框架的新手。我正在使用 MoQ 框架为控制器编写单元测试,这是我的测试方法,

var mockedItemDetail = new ItemDetail()
        {
            Name = null
        };

        var mockObject = new Mock<IItem>();
        mockObject.Setup(x => x.GetItemDetail()).Returns(mockedItemDetail);

        var result = myController.GetDetails() as ViewResult;

这是我的控制器方法,

public ActionResult GetDetails()
    {
        var controllerItemDetail = new ItemDetail();
        controllerItemDetail = _item.GetItemDetail();
        controllerItemDetail.Name = "Changed Name";
        return View("ViewName", controllerItemDetail);
    }

测试运行,现在我想断言发送的 mockedItemDetail 和接收的模型结果 controllerItemDetail。

在上述情况下,mockedItemDetail 属性“Name”为空,并且接收到的 controllerItemDetail 属性 Name 为“Changed Name”。

但是每当我调试时,调用测试方法GetDetails()后,

  1. 我的 mockedItemDetail 属性 Name 在当前范围内也更新为“Changed Name”,我不知道为什么?这是 MoQ 的实际行为吗?

编辑的内容

在下面的模拟列表中考虑与上述相同的情况,这里模拟对象的更改不会在所有上下文中更新。即 mockedItemDetailList 的列表计数保持为 0,而 controllerItemDetail 的列表计数为 1,即使在测试方法调用之后也是如此。为什么?

测试方法:

var mockedItemDetailList = new List<ItemDetail>();

    var mockObject = new Mock<IItem>();
    mockObject.Setup(x => x.GetListOfItemDetail()).Returns(mockedItemDetailList);

    var result = myController.GetDetails() as ViewResult;

控制器方法:

    public ActionResult GetDetails()
{
    var controllerItemDetail = new ItemDetail();
    controllerItemDetail = _item.GetListOfItemDetail();
    controllerItemDetail.Add(new ItemDetail(){
    Name = "Changed Name"
    });
    return View("ViewName", controllerItemDetail);
}

【问题讨论】:

  • 您正在为x.GetItemDetail() 返回一个特定对象。为什么它不会在当前上下文中更新?该对象正在controllerItemDetail.Name = "Changed Name"; 进行修改。这是预期的行为。
  • 嘲笑是一种罪
  • 请找到编辑后的内容@FrankerZ
  • 根据您发布的代码,我同意@FrankerZ,这是预期的行为(这也是第二个示例中的预期行为,两个变量都引用列表的同一个实例所以列表应该添加一个对象)。但是,很难从您发布的代码中看出模拟对象是如何注入到您的控制器中的。您是否将模拟对象 (IItem) 传递到控制器的构造函数中?

标签: c# unit-testing nunit moq moq-3


【解决方案1】:

你有一个非常具体的对象:

var mockedItemDetail = new ItemDetail()
{
    Name = null
};

当您调用mockObject.Setup(x =&gt; x.GetItemDetail()).Returns(mockedItemDetail); 时,您将返回对mockItemDetail 的引用。该对象的任何更改都会在所有上下文中更新。

快速跟进。要让它每次都返回一个空白的new ItemDetail(),你可以简单地使用Returns()的lambda方法:

mockObject.Setup(x => x.GetItemDetail()).Returns(() => new ItemDetail()
{
    Name = null
});

【讨论】:

  • 我同意你的观点。但是请解释一下编辑内容的原因?
  • 如果您希望每个 GetItemDetail() 返回一个新实例而不影响可能返回的 ItemDetail() 的其他版本,则为您提供一个替代方案。
  • 您似乎只是提供了另一种解决方案。但我想知道为什么同一个实例在第一种情况下更新而在第二种情况下没有更新(列表的情况)?
  • 因为每次运行 lambda 函数时都会返回一个新的 ItemDetail。调用 mockObject.Object.GetItemDetail() 将调用匿名函数 (lambada),该函数将生成一个新的 ItemDetail 并返回它,而不是(在第一个示例中)返回相同的特定对象。
猜你喜欢
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 2016-01-20
  • 2011-01-25
  • 2019-05-04
  • 2020-12-08
相关资源
最近更新 更多