【问题标题】:mocking collection behavior with Moq使用 Moq 模拟收集行为
【发布时间】:2010-06-15 23:05:56
【问题描述】:

我已经阅读了关于 Moq 用户组的一些讨论,但未能找到示例,并且到目前为止 无法找到我所拥有的场景。这是我的问题和代码:

// 6 periods
var schedule = new List<PaymentPlanPeriod>()
{
    new PaymentPlanPeriod(1000m, args.MinDate.ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(1).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(2).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(3).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(4).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(5).ToString())
};

// Now the proxy is correct with the schedule
helper.Setup(h => h.GetPlanPeriods(It.IsAny<String>(), schedule));

然后在我的测试中我使用 Periods 但 Mocked _PaymentPlanHelper 从不填充集合,请参阅下面的用法:

public IEnumerable<PaymentPlanPeriod> Periods
{
 get
 {
  if (CanCalculateExpression())
     _PaymentPlanHelper.GetPlanPeriods(this.ToString(), _PaymentSchedule);

  return _PaymentSchedule;
 }
}

现在,如果我将模拟对象更改为使用 GetPlanPeriods 的另一个重载方法,该方法返回一个 List,如下所示:

var schedule = new List<PaymentPlanPeriod>()
{
    new PaymentPlanPeriod(1000m, args.MinDate.ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(1).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(2).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(3).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(4).ToString()),
    new PaymentPlanPeriod(1000m, args.MinDate.Value.AddMonths(5).ToString())
};

helper.Setup(h => h.GetPlanPeriods(It.IsAny<String>())).Returns(new List<PaymentPlanPeriod>(schedule));

List<PaymentPlanPeriod> result = new _PaymentPlanHelper.GetPlanPeriods(this.ToString());

这按预期工作。只要你不抨击我的架构,任何指针都会很棒...... :)

谢谢你, 斯蒂芬

【问题讨论】:

  • 我是否正确,您希望您的模拟方法调用修改传递给它的调度参数?这个 SO 问题可能会有所帮助 - 答案使用回调 stackoverflow.com/questions/2183691/…
  • 是的,大卫。我现在正在阅读另一篇文章。谢谢。

标签: c# unit-testing moq


【解决方案1】:

Setup-Method 基本上是设置一些预期的行为。例如,设置一个 Mock-Instance 以返回某些值。例如配置模拟:

var configMock = new Mock<IConfiguration>();
configMock.Setup(c=>c.GetSetting("Title")).Returns("Hello Word");
configMock.Setup(c=>c.GetSetting("Answer")).Returns("42");

这意味着,当您将“Title”传递给 GetSetting-Method 时,mock 将返回“Hello Word”。当您将“答案”传递给模拟时,它将返回“42”。此外,您可以配置通配符。例如:

var configMock = new Mock<IConfiguration>();
configMock.Setup(c=>c.GetSetting(It.IsAny<String>())).Returns("Hello Word");

现在,对于任何对 GetSetting-Method 的调用,模拟都将返回字符串“Hello World”

现在,在您的第一种情况下,您以这种方式设置模拟:期望使用任何字符串和此列表调用 GetPlanPeriods。因此,您可以使用第二个参数指定您期望的列表。但是您没有为此调用设置任何 bahvior。

Afaik,您可以使用参数设置 Moq。像这样:

helper.Setup(c => c.GetPlanPeriods(It.IsAny<string>(),It.IsAny<List<PaymentPlanPeriod>>()))
            .Callback((string s, List<PaymentPlanPeriod> l)=>
                          {
                              l.Add(new PaymentPlanPeriod(1000m, args.MinDate.ToString()));
                          });

在第二个示例中,您以这种方式设置模拟:期望使用任何字符串调用 GetPlanPeriods,然后返回此列表。因此它将返回给定列表的任何调用。这就是它起作用的原因。

一般来说,我建议您以您是第二个示例的方式设计您的 API。宁愿返回更改的集合,而不是更新传递的集合。使用和模拟这些方法要容易得多。

【讨论】:

    猜你喜欢
    • 2011-01-13
    • 2011-06-13
    • 2019-09-11
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多