【问题标题】:How to write a moq test to setup a method to return a count value如何编写最小起订量测试来设置返回计数值的方法
【发布时间】:2015-04-01 11:11:38
【问题描述】:

在我的控制器操作中,每当添加新产品时,我都会在数据库中检查该产品编号是否不存在。此检查的代码如下所示

 public ActionResult Index(ProductModel model)
    {
      var productCount = _productsService.GetAll(true).Count(x => x.ProductNumber == model.ProductNumber);

      if (productCount > 0)
          ModelState.AddModelError("ProductNumber", Product already present in the system!");

       // more processing
     }

我是 MOQ 测试的新手,我正在尝试编写一个单元测试来设置 GetAll 方法,该方法将返回 0。我写过类似的东西,但它似乎不起作用

 var _productsService = new Mock<IProductsService>();
_productsService.Setup(m => m.GetAll(true).Count()).Returns(0);

有什么想法吗?谢谢

【问题讨论】:

  • 您要测试的功能究竟是什么?控制器方法还是 _productsService.GetAll()?
  • @greenhoorn 我想测试控制器动作,但在这个动作中我调用 GetAll 方法我需要设置它并获取一个值。
  • 您遇到错误了吗?
  • System.NotSupportedException : 表达式引用了不属于模拟对象的方法:m => m.GetAll(True).Count()
  • 方法'GetAll'是什么样子的?

标签: c# asp.net-mvc unit-testing moq


【解决方案1】:

这不是你使用 Moq 的方式——Count 很可能不是你的方法(它是 LINQ/其他 3rd 方),你不要嘲笑它。您需要模拟的是GetAll 方法,它是您的可模拟依赖项上的一个方法。您“告诉”GetAll 返回型号与参数匹配的产品,如下所示:

[Test]
public void Index_ReportsModelError_WhenProductAlreadyExists()
{
    const int ExistingProductNumber = 10;
    var _productsService = new Mock<IProductsService>();
    var existingProduct = new Product { ProductNumber = ExistingProductNumber };
    _productsService.Setup(m => m.GetAll(true)).Returns(new [] { existingProduct });

    controller.Index(new ProductModel { ProductNumber = ExistingProductNumber });

    // Assert
}

修复现有测试就像确保GetAll 永远不会返回与Index 参数中编号相同的产品一样简单:

const int ExistingProductNumber = 10;
const int NewProductNumber = 20;
var _productsService = new Mock<IProductsService>();
var existingProduct = new Product { ProductNumber = ExistingProductNumber };
_productsService.Setup(m => m.GetAll(true)).Returns(new [] { existingProduct });

controller.Index(new ProductModel { ProductNumber = NewProductNumber });

// Assert

【讨论】:

  • 我正在编写其他一些测试代码。我必须在控制器操作中添加此检查(即产品编号尚不存在),现在这些单元测试由于此更改而失败。我现在正在尝试弄清楚如何通过“添加 GetAll 检查并在 ModelState 中添加此错误”。我想设置类似的东西,此代码始终通过在添加此检查之前编写的单元测试。是的,当然我也可以添加一个新的单元测试来检查存储库上的 GetAll 方法。
  • @Learner:“当然,我也可以添加一个新的单元测试来检查存储库中的 GetAll 方法”——你为什么要这样做?你测试控制器,而不是GetAllGetAll 是对你的控制器的依赖,你把它存根(就像你现在做的那样)。您提到您添加了破坏测试的新功能。这需要更改测试——您需要确保GetAll 的现有设置永远不会返回与传递给Index 方法的产品编号相同的产品。
  • 感谢@jimmy_keen,您已经澄清了我的概念。有什么好的在线教程或关于使用存储库进行 Moq 测试的书籍或视频的推荐吗?
  • @Learner:为了与 Moq 相处,我建议他们的 wiki 页面 -- github.com/Moq/moq4/wiki/Quickstart。这种特殊情况(存储库测试)不需要任何特殊教程恕我直言......存储库只是您模拟的依赖项。你最好找一些关于 ASP.NET MVC 控制器单元测试的教程,网上有很多。
【解决方案2】:

看看这个帖子: Expression references a method that does not belong to the mocked object

他基本上也有同样的问题,你在模拟一个扩展方法Count()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多